<?
/**
 * VoiceOne Webservices Interface
 *
 * @package voiceone_webservices
 * @subpackage  interface
 */

//******************************************************************************
//******************               ENTITY                   ********************
//******************************************************************************

// ---- getEntity(id:int):entity[] ---------------------------------------------
/**
* Get the entities of VoiceOne. An Entity is a "VoiceOne object", such as extensions,
* offices, providers, trunks, and so on. The entities can be grouped in groups.
* The information given are the ID and the TYPE of entities. Nothing else.
*
* @param integer $id The entity ID or null if you want to get all the entities
* @return entityArray It returns a list of entities or the entity requested as describled in the wsdl structure (structs.php)
*/
function getEntity($id) {
  global $db;
  if ($id!="") $condition=" WHERE id=$id ";
  $qry="SELECT * FROM cw_entity $condition";
  $res=$db->Execute($qry);
  while ($arr=$res->FetchRow()) {
    $ret[]=$arr;
  }
  return $ret;
}

// ---- putEntity(ent:entity):int ----------------------------------------------
/**
* Insert an entity in the VoiceOne system. Usually this is a internal method,
* which is called inside other method. Use this function when you want to manually
* add a new object (i.e. queue). Before doing it, you have to create a new
* entity and then, with the resulting ID, add a new entry in the queues table
* with the same ID.
*
* @param Entity $ent It accept an Entity type variable as describled in the wsdl structure (structs.php)
* @return integer $id It returns the ID of the new entity
*/
function putEntity($ent) {
  global $db;
  $type=$ent["type"];
  if ($ent["id"]!="") {
    $id=$ent["id"];
    $oldentity=getEntity($id);
    if (!isset($oldentity[0])) $qry="INSERT INTO cw_entity (`id`,`type`) VALUES ($id, $type)";
    else $qry="UPDATE cw_entity SET `type`=$type WHERE id=$id";
  } 
  else $qry="INSERT INTO cw_entity (`type`) VALUES ($type)";
  $res=$db->Execute($qry);
  if ($res===false) $ret=0;
  else if ($ent["id"]!="") $ret=$ent["id"];
    else $ret=$db->Insert_ID();
  //if asterisk is ON, reload it
  $status=pbxSwitch("status");
  if($status=="ON") sendCommand("reload");
  //return
  return $ret;
}

// ---- delEntity(id:int):int --------------------------------------------------
function delEntity($id) {
  global $db;

  $qry="DELETE FROM cw_entity WHERE id=$id";
  $res=$db->Execute($qry);
  if ($res===false) $ret=0; else $ret=1;
  return $ret;
}

// ---- getEntityName(id:int):string ----------------------------------------------
function getEntityName($entity_id) {
  $entity=getEntity($entity_id);
  $entityType=$entity[0]["type"];
  switch ($entityType) {
    case EXTENSION:
      $entityArray=getClient($entity_id,0);
      $entityName=$entityArray[0]["extension"];
    break;
    case PROVIDER_ACCOUNT:
      $entityArray=getProviderAccount($entity_id,0);
      $entityName=$entityArray[0]["name"];
    break;
    case OFFICE:
      $entityArray=getOffice($entity_id);
      $entityName=$entityArray[0]["name"];
    break;
    case PHONENUMBER:
      $entityArray=getPhoneNumber($entity_id);;
      $entityName=$entityArray[0]["name"];
    break;
    case MISDN_GROUP:
      $g=getIsdnGroup($entity_id);
      $entityName=$g[0]["name"];
    break;
    case ZAPATA_GROUP:
      $g=getZapataGroup($entity_id);
      $entityName=$g[0]["name"];
    break;
    case APPLICATION:
      $g=getApplication($entity_id);
      $entityName="app-".$g[0]["name"];
    break;
    case QUEUE:
      $g=getQueue($entity_id);
      $entityName=$g[0]["name"];
    break;
    case CHANNEL:
      $entityName="trunk_out_".$entity_id;
    break;
  }
  return $entityName;
}

// ---- getMetaGroupFromEntity(id:int):int ----------------------------------------------
function getMetaGroupFromEntity($entity_id) {
  $entity=getEntity($entity_id);
  $entityType=$entity[0]["type"];
  switch ($entityType) {
    case EXTENSION:
      $ret=GROUP_OF_EXTENSION;
    break;
    case PROVIDER_ACCOUNT:
    case ZAPATA_GROUP:
    case MISDN_GROUP:
    case ZAPATA_GROUP:
    case CHANNEL:
      $ret=GROUP_OF_RESOURCE;
    break;
    case OFFICE:
      $ret=GROUP_OF_OFFICE;
    break;
    case PHONENUMBER:
      $ret=GROUP_OF_PHONENUMBER;
    break;
    case APPLICATION:
      $ret=GROUP_OF_APPLICATION;
    break;
  }
  return $ret;
}

// ---- getMetaGroupFromGroup(id:int):int ----------------------------------------------
function getMetaGroupFromGroup($group_id) {
  $qry="SELECT * FROM `cw_group` WHERE `id`=".$group_id;
  $res=$db->Execute($qry);
  while ($arr=$res->FetchRow()) {
    $ret=$arr["type"];
  }
  return $ret;
}

// ---- addEntityToGroup(entity_id:int, extensions:ExtensionArray, groups:intArray):int

function addEntityToGroup($entity_id,$groups) {
  global $db;
  $ret=1;

  //get the Entity Name that is the context to be included
  $context=getEntityName($entity_id);


  //Add the entity to the meta group
  $metaGroup=getMetaGroupFromEntity($entity_id);
  if ($metaGroup!=GROUP_OF_OFFICE) {
    $groupArr=getGroup($metaGroup);
    $includeContext=$groupArr[0]["name"];
    $res=putAstConfig("extensions.conf", $includeContext, "include", $context);
    if ($res===false) $ret=$ret and 0; else $ret=$ret and 1;
  }

  //add the metagroup to the group list
  $groups[]=$metaGroup;

  //add the extensions in extensions_table
  //add the entity to the groups into the cw_group_entity
  if (is_array($groups))
  foreach ($groups as $group_id) {

    $qry="SELECT * FROM cw_group_entity WHERE `group_id`=$group_id AND `entity_id`=$entity_id";
    $res=$db->Execute($qry);
    if ($res->RecordCount()==0) {
      $qry="INSERT INTO cw_group_entity (`group_id`,`entity_id`) VALUES ($group_id, $entity_id)";
      $res=$db->Execute($qry);
      if ($res===false) return false;
    }
  }

  //create the global var in the Ast_Config
  generateGlobalVar($groups);

  if ($res===false) $ret=$ret and 0; else $ret=$ret and 1;
  return $ret;
}

// ---- removeEntityFromGroup(entity_id: int):int

function removeEntityFromGroup($entity_id) {
  global $db;

  $entityName=getEntityName($entity_id);

  //remove the entity from the relations between entities and groups
  $db->Execute("DELETE FROM cw_group_entity WHERE entity_id=$entity_id");

  if (trim($entityName)!="") {
    //remove the entry from the ast_config
    //$res=delAstConfig("extensions.conf",$entityName,"switch");
    //$res=delAstConfig("extensions.conf",$entityName,"exten");
    //$res=delAstConfig("extensions.conf",$entityName,"include",$entityName);

    //delete the extensions from the extensions_table
    //$db->Execute("DELETE FROM extensions_table WHERE context='$entityName'");

    $res=delAstConfig("extensions.conf","%","include",$entityName);
  }

  //regenerate the global var from the ast config
  //generateGlobalVar();

  //$ret=delEntity($entity_id);
  return $ret;
}

//******************************************************************************
//******************              EXTENSION                 ********************
//******************************************************************************

// ---- getExtension(id:int):Extension[] ---------------------------------------
function getExtension($id){
  global $db;
  if ($id!="") $condition=" WHERE id=$id ";
  $qry="SELECT * FROM cw_extension $condition";
  $res=$db->Execute($qry);
  $ret=array();
  while ($v=$res->FetchRow()) $ret[]=$v;
  return $ret;
}

// ---- getExtensionByExtension(exten:string):Extension[] ----------------------
function getExtensionByExtension($exten){
  global $db;
  if ($exten!="") $condition=" WHERE extension='".string2sql($exten)."' ";
  $qry="SELECT * FROM cw_extension $condition";
  $res=$db->Execute($qry);
  $ret=array();
  while ($v=$res->FetchRow()) $ret[]=$v;
  return $ret;
}

// ---- putExtension(extension:Extension):int ----------------------------------
function putExtension($extension){
  global $db;
  $entity_id=$extension["entity_id"];
  $exten=$extension["extension"];
  if(($entity_id==0)or($exten=="")) return 0;
  $qry="INSERT INTO cw_extension (id,entity_id,extension) ";
  $qry.="VALUES (NULL, ".$entity_id.", '".string2sql($exten)."')";
  $res=$db->Execute($qry);
  if ($res===false) return 0;
  else return 1;
}

// ---- delExtension(id:int):int -----------------------------------------------
function delExtension($id){
  global $db;
  $qry="DELETE FROM cw_extension WHERE id=$id";
  $res=$db->Execute($qry);
  if ($res===false) return 0;
  else return 1;
}
// ---- delExtensionByExtension(exten:string):int ------------------------------
function delExtensionByExtension($exten){
  global $db;
  $qry="DELETE FROM cw_extension WHERE extension='".string2sql($exten)."'";
  $res=$db->Execute($qry);
  if ($res===false) return 0;
  else return 1;
}
// ---- delExtensionByEntity(id:int):int -----------------------------------------------
function delExtensionByEntity($id){
  global $db;
  $qry="DELETE FROM cw_extension WHERE entity_id=$id";
  $res=$db->Execute($qry);
  if ($res===false) return 0;
  else return 1;
}

// ---- getNextSpeedDial():int -------------------------------------------------
//private
function getNextSpeedDial() {
  global $db;
  //get exsisting speedDials
  $allExtensions=getExtension(0);
  if(is_array($allExtensions)){
    foreach($allExtensions as $e) $speedDials[]=$e["extension"];
  }
  //return the first available speedDial
  $next=1;
  $nextSD=$next."*";
  if(is_array($speedDials)){
    while(in_array($nextSD,$speedDials)){
      $next++;
      $nextSD=$next."*";
    }
    return $nextSD;
  }
  else return "1*";
}

//******************************************************************************
//******************               CLIENT                   ********************
//******************************************************************************

// ---- getClientAccount(id:int, technology:int):client[] ----------------------
function getClientAccount($id,$technology=0) {
  $clients=getClient($id,$technology);
  foreach($clients as $client){
    if(isset($client["password"])) $client["password"]="";
    if(isset($client["voicemail"]["password"])) $client["voicemail"]["password"]="";
    $ret[]=$client;
  }
  return $ret;
}

// ---- putClientAccount(client:Client,oldpwd:String,newpwd:String):int --------
function putClientAccount($id,$tech,$language,$oldpwd="",$newpwd="",$vmail="",$voldpwd="",$vnewpwd=""){
  if(!(isset($id)and($id!=""))) return 0;
  //extract existent client's definition
  $clients=getClient($id,$tech);
  if(is_array($clients)) $client=$clients[0];
  else return 0;
  //set new password
  if(($oldpwd!="")&&($newpwd!="")){
    if($oldpwd==$client["password"]) $client["password"]=$newpwd;
    else return -1;
  }
  //set new language
  if($language!="") $client["language"]=$language;
  //set new voicemail
  if (count($client["voicemail"])>0) {
    $client["voicemail"]["email"]=$vmail;
    if(($voldpwd!="")&&($vnewpwd!="")){
      if($voldpwd==$client["voicemail"]["password"]) $client["voicemail"]["password"]=$vnewpwd;
      else return -2;
    }
  }
  //save new client definition
  $ret=putClient($client);
  return $ret;
}

// ---- getClient(id:int, technology:int):client[] -----------------------------
function getClient($id,$technology=0) {
  global $db;
  if ($id!="") $condition=" WHERE id=$id ";
  else if ($technology!=0) $condition=" WHERE technology=$technology";
  $qry="SELECT * FROM cw_client $condition ORDER BY extension";
  $res=$db->Execute($qry);
  while ($v=$res->FetchRow()) {
    //extract some variables
    $id=$v["id"];
    $extension=$v["extension"];
    //retrieve the client specific options
    $v["options"]=getEntityOption($id);
    //retrieve the client groups
    $qry="SELECT * FROM cw_group_entity  WHERE entity_id=$id";
    $resGrp=$db->Execute($qry);
    while ($arr=$resGrp->FetchRow()) $v["groups"][]=$arr["group_id"];
    //retrieve the voicemail
    $voicemail=getVoiceMail($extension);
    $v["voicemail"]=$voicemail[0];
    //retrieve the language
    $qry="SELECT * FROM cw_user WHERE entity_id=$id";
    $resUsr=$db->Execute($qry);
    while ($arr=$resUsr->FetchRow()) $v["language"]=$arr["lang"];
    //define ret
    $ret[]=$v;
  }
  return $ret;
}

// ---- putClient(client:Client):int -------------------------------------------
function putClient($client) {
  global $db,$realm,$API_PROXY_enabled;
  $entity=array();
  //check if extension is numeric
  if (!is_numeric($client['extension'])) return 0;
  //if already exists, delete it
  if (isset($client["id"]) and $client["id"]!="") {
    $channel["id"]=getChannelFromEntity($client["id"]);
    //get related agent
    $old_agentId=0;
    $old_agentId=getAgentFromEntity($client["id"]);
    if($old_agentId!=0){
    	$old_agentArr=getAgent($old_agentId);
    	$agent["id"]=$old_agentArr[0]["id"];
    	$agent["joined_queues"]=$old_agentArr[0]["joined_queues"];
    }
    //retrive the already binded user, if exists, to maintain the old user id and type
    $resUsr=$db->Execute("SELECT * FROM cw_user WHERE entity_id=".$client["id"]);
    while ($arru=$resUsr->FetchRow()) {
      $userId=$arru["id"];
      $userType=$arru["type"];
    }
    //retrieve the provisioning options
    $oldProvClient=getProvClientFromEntity($client["id"]);    
    //delete client
    delClient($client["id"],false);
    $entity["id"]=$client["id"];
  }
  //create a new entity
  $entity["type"]=EXTENSION;
  $entity_id=putEntity($entity);
  if (is_object($entity_id) or $entity_id==0) return 0;
  //extract the rule set ID
  $rule=extractRuleFromOption($client["options"],$client["technology"]);
  //insert the client credentials
  $qry="INSERT INTO cw_client (id,name,surname,extension,alias,username,password,rule,technology) ";
  $qry.="VALUES ($entity_id,'".string2sql($client['name'])."','".string2sql($client['surname'])."',";
  $qry.="'".string2sql($client['extension'])."','".string2sql($client['alias'])."','".string2sql($client['username'])."',";
  $qry.="'".string2sql($client['password'])."',$rule,".$client['technology'].")";
  $res=$db->Execute($qry);
  if ($res===false) $ret=$ret and 0; else $ret=$ret and 1;
  //manage per-technology options
  switch($client["technology"]){
    case MISDN:
      //extract port option and set channel resource
      $portsOptionArr=getOptionByName("ports","mISDN");
      $portsOptionId=$portsOptionArr[0]["id"];
      foreach ($client["options"] as $k=>$v){
        if($v["key"]==$portsOptionId) $port=$v["value"];
      }
      $resource=$port."/".$client["extension"];
      break;
    case ZAP:
      //extract channel option and set channel resource
      $channelOptionArr=getOptionByName("channel","ZAP");
      $channelOptionId=$channelOptionArr[0]["id"];
      foreach ($client["options"] as $k=>$v){
        if($v["key"]==$channelOptionId) $zchannel=$v["value"];
      }
      $resource=$zchannel; //$resource=$zchannel."/".$client["extension"];
      //extract signalling and set it in otheroption array
      $signalling="";
      if((function_exists(getZapataChannel))&&($zchannel!=0)){
        $ret=getZapataChannel(0);
        if(is_array($ret)){
          foreach($ret as $c){
            if($c["zchannel"]==$zchannel){
              $signalling=$c["signalling"];
              break;
            }
          }
        }
      }
      $client["signalling"]=$signalling;
      break;
    default:
      $resource=$client["extension"];
      break;
  }
  //write the options in the asterisk table
  putEntityOption($client["options"], $client["technology"], $entity_id, $client);
  $ret=1;
  //get the tech infos
  $techArr=getTechnology($client["technology"]);
  $techName=$techArr[0]["name"];
  $techVoip=$techArr[0]["voip"];
  //set some variables
  $context=$client["extension"];
  $extension=$client["extension"];
  $alias=$client["alias"];
  $channelName=$techName."/".$extension;
  //put the new Channel
  $channel['technology']=$client["technology"];
  $channel['resource']=$resource;
  $channel["rule"]=$rule;
  $channel['key']=$entity_id;
  $channelId=putChannel($channel);
  //help text for viewAstConfig
  putAstConfig("extensions.conf", $context, "", "", $extension." - ".$client["name"]." ".$client["surname"]." - ".$channelName);
  //Hint
  putAstConfig("extensions.conf", $context, "exten", "$extension,hint,$channelName");
  putAstConfig("extensions.conf", $context, "exten", "$extension,1,AGI(dial.php,entity=$entity_id&group=".GROUP_OF_EXTENSION."&extension=$extension)");
  if($alias!="") putAstConfig("extensions.conf", $context, "exten", "$alias,1,Goto($extension,1)");
  //add the entity to the selected groups
  $res=addEntityToGroup($entity_id, $client["groups"]);
  if ($res===false) $ret=$ret and 0; else $ret=$ret and 1;
  //return value
  if ($ret==1) $ret=$entity_id; else $ret=0;
  //insert a new user for the web administration
  if ($ret>0) putUser(array("id"=>$userId,"type"=>$userType, "entity_id"=>$entity_id, "lang"=>$client["language"]));
  //insert the voicemail
  if (isset($client["voicemail"])) $ret=putVoiceMail($client["voicemail"]);
  //insert entry in cw_extension
  if($ret>0){
    $entry=array();
    $entry["id"]=0;
    $entry["entity_id"]=$entity_id;
    $entry["extension"]=$client['extension'];
    $ret=putExtension($entry);
		if($client["alias"]!=""){
      $entry=array();
      $entry["id"]=0;
      $entry["entity_id"]=$entity_id;
      $entry["extension"]=$client['alias'];
      $ret=putExtension($entry);
		}
  }
  //create associated agent
  if($ret>0){
    $agent["client"]=$entity_id;
    $agent["extension"]=$client['extension'];
    $agent["username"]="";
    $agent["password"]="";
    putAgent($agent);
  }
  //create entry for provisioving
  if($ret>0){
    if(is_array($oldProvClient)) $ret=putProvClient($oldProvClient);
    else $ret=touchProvClient(0,$entity_id);
  }
  //overwrite linked virtual extension
  if($ret>0){
  	$virtual=getVirtualExtensionFromClient($client["id"]);
  	if(($virtual!=0)&&(is_array($virtual))){
    	$ret=putVirtualExtension($virtual);
    }
  }
  //refresh asterisk proxy manager
  if($API_PROXY_enabled!=0) ast_writeProxyUsers();
  //if asterisk is ON, reload extensions and tech driver
  $status=pbxSwitch("status");
  if(($ret>0)and($status=="ON")){
    //reload technology driver
    switch($client["technology"]){
      case MISDN:
        if(function_exists(reloadmISDNDriver)) reloadmISDNDriver();
        break;
      case ZAP:
        if(function_exists(reloadZapDriver)) reloadZapDriver();
        break;
    }
    //send reload
    sendCommand("reload");
  }
  //set return
  return $ret;
}

// ---- delClient(id:int):int --------------------------------------------------
function delClient($entity_id, $reload=true) {
  global $db,$API_PROXY_enabled;
  //retrieve the tech type from the client
  $qry="SELECT * FROM cw_client WHERE id='".string2sql($entity_id)."'";
  $res=$db->Execute($qry);
  $arr=$res->FetchRow();
  $extension=$arr["extension"];
  $alias=$arr["alias"];
  $tech=$arr["technology"];
  $name=$arr["extension"];
  //remove client specific options
  $ret=delEntityOption($entity_id,$tech);
  //delete the Channel
  $channelId=getChannelFromEntity($entity_id);
  if ($channelId!=0) delChannel($channelId);
  //remove the client from the auxiliary table
  $qry="DELETE FROM cw_client WHERE id=".$entity_id;
  $db->Execute($qry);
  //remove the user from the user table, so it delete the account to voiceone
  $qry="DELETE FROM cw_user WHERE entity_id=".$entity_id;
  $db->Execute($qry);
  //remove the entry from the ast_config
  if($name!="") $res=delAstConfig("extensions.conf",$name);
  //delete the extensions from the extensions_table
  $db->Execute("DELETE FROM extensions_table WHERE context='$name'");
  //remove all the client inclusions
  if(trim($name)!="") $res=delAstConfig("extensions.conf","%","include",$name);
  //remove the client from the asterisk tables and groups
  $ret=removeEntityFromGroup($entity_id);
  //remove the entity
  $ret=delEntity($entity_id);
  //delete the VoiceMail
  $ret=delVoiceMail($name);
  //delete associated agent
  $ret=delAgent(getAgentFromEntity($entity_id));
  //delete from cw_extension
  $ret=delExtensionByExtension($extension);
  if(trim($alias)!="") $ret=delExtensionByExtension($alias);
  //delete provisioning client
  $provClient=getProvClientFromEntity($entity_id);
  if(is_array($provClient)) $ret=delProvClient($provClient["id"]);
  //refresh asterisk proxy manager
  if($API_PROXY_enabled!=0) ast_writeProxyUsers();
  //if asterisk is ON, reload extensions
  if($reload==true){
    $status=pbxSwitch("status");
    if($status=="ON"){
      //reload technology driver
      switch($tech){
        case MISDN:
          if(function_exists(reloadmISDNDriver)) reloadmISDNDriver();
          break;
        case ZAP:
          if(function_exists(reloadZapDriver)) reloadZapDriver();
          break;
      }
      //send reload
      sendCommand("reload");
    }
  }
  return $ret;
}

// ---- gelClientFromExtension(extension:string):client ------------------------
function gelClientFromExtension($extension) {
  global $db;
	$clients=getClient(0,0);
  if(is_array($clients)){
  	foreach($clients as $client){
      if($extension==$client["extension"]){ 
  		  $ret=$client;
        break;
      }
  	}
    return $ret;
  }
  else return 0;
}

//******************************************************************************
//*******************               CID                   **********************
//******************************************************************************

// ---- getCid(trunk_id:int, ext_id:int):Cid[] ---------------------------------
function getCid($trunk_id=0,$ext_id=0) {
  global $db;
  if ($trunk_id!=0) $condition=" WHERE trunk=$trunk_id ";
  else if ($ext_id!=0) $condition=" WHERE extension=$ext_id";
  $qry="SELECT * FROM cw_cid $condition ORDER BY extension";
  $res=$db->Execute($qry);
  while ($v=$res->FetchRow()) $ret[]=$v;
  return $ret;
}

// ---- putCid(exten_id:int,cid:Cid[]):int -------------------------------------
function putCid($exten_id,$cidArr) {
  global $db;
  //delete old cid settings
  $ret=delCid(0,$exten_id);
  if($ret!=0){
    //insert new cid
    if (is_array($cidArr)){
    	foreach($cidArr as $cid){
    	  $id=$cid["id"];
    		$trunk_id=$cid["trunk"];
    		$clir=$cid["clir"];
        $cid_number=$cid["cid_number"];
    		$cid_name=$cid["cid_name"];
    		$qry="INSERT INTO cw_cid (id,trunk,extension,clir,cid_number,cid_name) ";
      	$qry.="VALUES ($id,$trunk_id,$exten_id,$clir,'".string2sql($cid_number)."','".string2sql($cid_name)."')";
      	$res=$db->Execute($qry);
      	if ($res===false) $ret=$ret and 0; else $ret=$ret and 1;
    	}
  		return $ret;
  	}else return 0;
  }else return 0;
}

// ---- delCid(trunk_id:int, ext_id:int):int -----------------------------------
function delCid($trunk_id=0,$ext_id=0) {
  global $db;
  if ($trunk_id!=0) $condition=" WHERE trunk=$trunk_id ";
  else if ($ext_id!=0) $condition=" WHERE extension=$ext_id";
  $qry="DELETE FROM cw_cid $condition";
  $res=$db->Execute($qry);
  if($res===false) return 0; else return 1;
}
// ---- getCidFromTrunk(trunk_id:int):Cid[] ---------------------------------
function getCidFromTrunk($trunk_id) {
  global $db;
  if(($trunk_id==0)||(trim($trunk_id)=="")) return 0; 
  $channel_id=getChannelFromEntity($trunk_id);
	if(($channel_id==0)||(trim($channel_id)=="")) return 0;
  $qry="SELECT * FROM cw_cid WHERE trunk=".$channel_id." ORDER BY extension";
  $res=$db->Execute($qry);
  while ($v=$res->FetchRow()) $ret[]=$v;
  return $ret;
}
// PRIVATE ---- pruneCidClient(trunk_id:int, numberArr:Array):int --------------
function pruneCidClient($trunk_id,$numberArr){
  global $db;
  //check input values
  if(($trunk_id==0)||(trim($trunk_id)=="")) return 0;
  //delete cid setting linked to a number which is not in the list
  if(is_array($numberArr)){
    $notInList="";
  	foreach($numberArr as $number){
    	$notInList.="'".$number."',";
    }
    if(strlen($notInList)<2) return 0;
    $notInList=substr($notInList,0,-1);
  	$qry="DELETE FROM cw_cid WHERE trunk='".$trunk_id."' AND cid_number NOT IN (".$notInList.") ";
  }else{
  	$qry="DELETE FROM cw_cid WHERE trunk='".$trunk_id."' ";
  }
  $res=$db->Execute($qry);
  if($res===false) return 0; else return 1;
}
//******************************************************************************
//******************               OFFICE                   ********************
//******************************************************************************

// ---- getOffice(id:int):Office[] ---------------------------------------------
function getOffice($id) {
  global $db;
  //Retrieve Office
  if ($id!="") $condition=" WHERE id=$id ";
  $qry="SELECT * FROM cw_office ".$condition." ORDER BY name";
  $res=$db->Execute($qry);
  while($v=$res->FetchRow()) {
    //set alias
    if($v["alias"]!="") $v["alias"]=split("\|",$v["alias"]); 
    else $v["alias"]=array();
    //retrieve the office specific options
    $v["options"]=getEntityOption($id);
    //retrieve the speed dial
    $channel=getChannel(getChannelFromEntity($v["id"]),0);
    $v["speeddial"]=substr($channel[0]["speeddial"],0,-1);
    //retrieve the phone numbers
    $v["numbers"]=$channel[0]["cid_list"];
    $v["did"]=$channel[0]["did"];
    //retrieve CID settings
    $v["enable_cid"]=$channel[0]["enable_cid"];
    $v["force_cid"]=$channel[0]["force_cid"];
    $v["clir"]=$channel[0]["clir"];
    $v["cid_number"]=$channel[0]["cid_number"];
    $v["cid_name"]=$channel[0]["cid_name"];
    $v["cid_appexten"]=$channel[0]["cid_appexten"];
    //retrieve the office groups
    $qry="SELECT * FROM cw_group_entity WHERE entity_id=".$v["id"];
    $resg=$db->Execute($qry);
    while ($arr=$resg->FetchRow()) $v["groups"][]=$arr["group_id"];
    //prepare ruturn struncture
    $ret[]=$v;
  }
  return $ret;
}

// ---- putOffice(dep:Office):int ---------------------------------------------
function putOffice($dep) {
  global $db,$voiceoneWSDocumentRoot,$voTools,$keyName,$outgoing_prefix; 
  //If already exists, retrieve information and delete it
  $entity=array();
  if (isset($dep["id"]) and $dep["id"]!="") {
    $old_channel=getChannel(getChannelFromEntity($dep["id"]));
    $channel["id"]=$old_channel[0]["id"];
    $channel["order"]=$old_channel[0]["order"];
    delOffice($dep["id"],false);
    $entity["id"]=$dep["id"];
  }
  //Create a new entity
  $entity["type"]=OFFICE;
  $entity_id=putEntity($entity);
  if (is_object($entity_id) or $entity_id==0) return 0;
  //Extract the rule set Id
  $rule=extractRuleFromOption($dep["options"],IAX2);
  //Insert the client credentials
  $name=$dep["name"];
  $label=$dep["label"];
  $username=$dep["username"];
  $password=$dep["password"];
  $inkey=$dep["inkey"];
  $host=$dep["host"];
  $port=$dep["port"];
  $register=$dep["register"];
  $alias=msns2string($dep["alias"]);
  $qry="INSERT INTO cw_office (id,name,label,username,password,inkey,host,port,register,alias,rule) ";
  $qry.="VALUES ($entity_id,'".string2sql($name)."','".string2sql($label)."','".string2sql($username)."','".string2sql($password)."',";
  $qry.="'".string2sql($inkey)."','".string2sql($host)."','".string2sql($port)."','".string2sql($register)."','".string2sql($alias)."',$rule)";
  $res=$db->Execute($qry);
  if ($res===false) return 0;
  //Write the options in the asterisk table
  putEntityOption($dep["options"], IAX2, $entity_id, $dep);
  //Put the Channel
  $channel["technology"]=IAX2;
  $channel["resource"]=$dep["name"];
  $channel["rule"]=$rule;
  $channel['key']=$entity_id;
  $channel['speeddial']=$dep["speeddial"];
  $channel['trunk']=1;
  $channel['did']=$dep["did"];
  if($dep["did"]==1) $channel['msns']=Array("X"); else $channel['msns']=null;
  $channel['enable_cid']=$dep["enable_cid"];
  $channel['cid_list']=$dep["numbers"];
  $channel['cid_name']=$dep["cid_name"];
  $channel['cid_number']=$dep["cid_number"];
  if($dep["cid_appexten"]=="") $dep["cid_appexten"]=0; $channel['cid_appexten']=$dep["cid_appexten"];
  if($dep["force_cid"]=="") $dep["force_cid"]=0; $channel['force_cid']=$dep["force_cid"];
  if($dep["clir"]=="") $dep["clir"]=0; $channel['clir']=$dep["clir"];  
  $channelId=putChannel($channel);
  //Add the entity to the selected groups
  $res=addEntityToGroup($entity_id, $dep["groups"]);
  if ($res===false) $ret=0; else $ret=1;
  //Get the tech infos
  $techArr=getTechnology(IAX2);
  $techRealTime = $techArr[0]["realtime"];
  $techTable    = $techArr[0]["table"];
  $techFile     = $techArr[0]["config_file"];
  //Update the incoming context
  if ($techRealTime==1) {
    $qry="UPDATE $techTable set context='".string2sql("trunk_".$channelId)."' WHERE name='".string2sql($dep["name"])."'";
    $db->Execute($qry);
  } else {
    $res=delAstConfig($techFile, $dep["name"], "context");
    $res=putAstConfig($techFile, $dep["name"], "context", "trunk_".$channelId);
  }
  //Register the provider
  if ($register=="1" and $host!="") {
    if ($password!="") putAstConfig($techFile, "general", "register", $dep["username"].":".$dep["password"]."@".$dep["host"]);
    else if ($inkey!="") putAstConfig($techFile, "general", "register", $dep["username"].":[".$keyName."]@".$dep["host"]);
    else putAstConfig($techFile, "general", "register", $dep["username"]."@".$dep["host"]);
  }
  //Insert numbers in the ast_config
  $context="trunk_out_".$channelId;
  if (is_array($dep["alias"]))
  foreach ($dep["alias"] as $n) {
    putAstConfig("extensions.conf",$context,"exten",$outgoing_prefix.$n.",1,AGI(dial.php,entity=$entity_id&group=".GROUP_OF_OFFICE."&extension=".$outgoing_prefix.$n.")");
  }
  /*
  //insert the office context
  $context=$dep["name"];
  $channelId=getChannelFromEntity($entity_id);
  if (asteriskRealtime===true)
    putExtension(Array("context" => $context, "exten"=>"s", "priority"=>1, "app"=>"include",  "appdata"=>"trunk_out_".$channelId));
  else
    putAstConfig("extensions.conf",$context,"exten","s,1,include(trunk_out_".$channelId.")");
  */
  //Insert phonenumbers in the cw_extension
  if (is_array($dep["alias"]))
  foreach ($dep["alias"] as $n) {
    $entry=array();
    $entry["entity_id"]=$entity_id;
    $entry["extension"]=$n;
    $res=putExtension($entry);
  }
  //Create the inkey file in the sandbox
  $inkeyFilename=$dep["name"];
  file_put_contents ( $voiceoneWSDocumentRoot."/sandbox/".$inkeyFilename.".pub", $dep["inkey"] );
  //Move the office rsa key in the proper location
  exec("sudo $voTools inkey \"$voiceoneWSDocumentRoot/sandbox/$inkeyFilename\"",$output,$retScript);
  //if asterisk is ON, reload extensions
  $status=pbxSwitch("status");
  if($status=="ON") {
    sendCommand("init keys");
    sendCommand("reload");
  }
  //Set return value
  return $entity_id;
}

// ---- delOffice(id:int):int -------------------------------------------------
function delOffice($entity_id,$reload=true) {
  global $db;
  //retrieve office information
  $resArr=getOffice($entity_id);
  $office=$resArr[0];
  //Remove the office from the asterisk tables and groups
  $ret=removeEntityFromGroup($entity_id);
  //Remove office specific options
  $ret=delEntityOption($entity_id,IAX2);
  //Delete the Channel
  $channelId=getChannelFromEntity($entity_id);
  if(($reload===true)&&($channelId!=0)) delChannel($channelId);
  //Remove the office from voiceone table
  $qry="DELETE FROM cw_office WHERE id=".$entity_id;
  $res=$db->Execute($qry);
  if ($res===false) $ret=0; else $ret=1;
  //delete the registration of the provider
  if ($office["username"]!="")
    delAstConfig("iax.conf", "general", "register", $office["username"]."%" );
  /*
  //delete the office context
  if ($office["name"]!="") delAstConfig("extensions.conf", $office["name"], "include");
  */
  //delete speeddial from cw_extension
  delExtensionByExtension($office["speeddial"]);
  //delete alias from cw_extension
  delExtensionByEntity($entity_id);
  //remove the entity
  $ret=delEntity($entity_id);
  //if asterisk is ON, reload extensions
  if($reload===true) {
    $status=pbxSwitch("status");
    if($status=="ON") sendCommand("reload");
  }
  return $ret;
}

//******************************************************************************
//******************               PROVIDER                 ********************
//******************************************************************************

// ---- getProvider(id:int):Provider[] ----------------------------------------
function getProvider($id) {
  global $db;
  // get providers
  if ($id!="") $condition=" WHERE id=$id ";
  $qry="SELECT * FROM cw_provider $condition";
  $resProv=$db->Execute($qry);
  while ($v=$resProv->FetchRow()) {
    $id=$v["id"];
    $v["accounts"]=getProviderAccount(0,$id);
    $ret[]=$v;
  }
  return $ret;
}

// ---- getProviderAccount(id:int,provider:int):ProviderAccount[] -------------
function getProviderAccount($id,$provider) {
  global $db;
  // get accounts
  if ($id!="") $condition=" WHERE id=$id ";
  else if ($provider!="") $condition=" WHERE provider=$provider ";
  $qry="SELECT * FROM cw_provider_account $condition";
  $resAcc=$db->Execute($qry);
  while ($account=$resAcc->FetchRow()) {
    //retrieve the account specific options
    $account["options"]=getEntityOption($account["id"]);
    //retrieve the speed dial
    $channel=getChannel(getChannelFromEntity($account["id"]),0);
    $account["speeddial"]=substr($channel[0]["speeddial"],0,-1);
    //retrieve the phone numbers
    $account["numbers"]=$channel[0]["cid_list"];
    $account["did"]=$channel[0]["did"];
    //retrieve CID settings
    $account["enable_cid"]=$channel[0]["enable_cid"];
    $account["force_cid"]=$channel[0]["force_cid"];
    $account["clir"]=$channel[0]["clir"];
    $account["cid_number"]=$channel[0]["cid_number"];
    $account["cid_name"]=$channel[0]["cid_name"];
    $account["cid_appexten"]=$channel[0]["cid_appexten"];
    $ret[]=$account;
  }
  return $ret;
}

// ---- putProvider(res:Provider):int -----------------------------------------
function putProvider($res) {
  global $db;
  $provider_id=0;
  //if account already exists delete and create a new entry
  if (isset($res["id"]) and $res["id"]!="") {
    delProvider($res["id"],false);
    $provider_id=$res["id"];
  }
  //insert the provider credentials
  $qry="INSERT INTO cw_provider (id,name,host,port,technology) ";
  $qry.="VALUES ($provider_id,'".string2sql($res['name'])."','".string2sql($res['host'])."',";
  $qry.="'".string2sql($res['port'])."',".$res['technology'].")";
  $ret=$db->Execute($qry);
  if ($ret===false) return 0;
  $qry="SELECT id FROM cw_provider ";
  $qry.="WHERE name='".string2sql($res['name'])."' ";
  $qry.="AND host='".string2sql($res['host'])."' ";
  $qry.="AND port='".string2sql($res['port'])."' ";
  $qry.="AND technology=".$res['technology'];
  $ret=$db->Execute($qry);
  if ($ret===false) return 0; 
  else {
    $provider=$ret->FetchRow();
    return $provider["id"];
  }
}

// ---- putProviderAccount(res:ProviderAccount):int ---------------------------
function putProviderAccount($res) {
  global $db;
  //check provider and retrieve informations
  if (!(isset($res["provider"]) and $res["provider"]!="")) return 0;
  $providerArr=getProvider($res["provider"]);
  if (!(is_array($providerArr))) return 0;
  $provider=$providerArr[0];
  $res["p_name"]=$provider["name"];
  $res["technology"]=$provider["technology"];
  $res["host"]=$provider["host"];
  //$res["port"]=$provider["port"]; // Now an account has its own port
  //if account already exists delete and create a new entry
  $entity=array();
  if (isset($res["id"]) and $res["id"]!="") {
    $old_channel=getChannel(getChannelFromEntity($res["id"]));
    $channel["id"]=$old_channel[0]["id"];
    $channel["order"]=$old_channel[0]["order"];
    delProviderAccount($res["id"],false);
    $entity["id"]=$res["id"];
  }
  //create a new entity
  $entity["type"]=PROVIDER_ACCOUNT;
  $entity_id=putEntity($entity);
  if (is_object($entity_id) or $entity_id==0) return 0;
  //extract the rule set ID
  $rule=extractRuleFromOption($res["options"],$res["technology"]);
  //insert the provider credentials
  $qry="INSERT INTO cw_provider_account (id,name,provider,port,username,password,allow_in,contact_extension,rule) ";
  $qry.="VALUES ($entity_id,'".string2sql($res['name'])."','".$res['provider']."','".string2sql($res['port'])."','".string2sql($res['username'])."',";
  $qry.="'".string2sql($res['password'])."','".$res['allow_in']."','".string2sql($res['contact_extension'])."',$rule)";
  $r=$db->Execute($qry);
  if ($r===false) $ret=$ret and 0; else $ret=$ret and 1;
  //perform other action if it is a VoIP provider
  if ($res["technology"]>0) {
    //write the options in the asterisk table
    putEntityOption($res["options"], $res["technology"], $entity_id, $res);
    //extract the phone number
    if (is_array($res["numbers"])) $numbers=implode("|",$res["numbers"]);
    else $numbers=array($res["username"]);
    //put the Channel
    $channel["technology"]=$res["technology"];
    $channel["resource"]=$res["name"];
    $channel["rule"]=$rule;
    $channel["msns"]=$res["numbers"];
    $channel['key']=$entity_id;
    $channel['speeddial']=$res["speeddial"];
    $channel['trunk']=1;
    $channel['did']=$res["did"];
    $channel['enable_cid'] = $res["enable_cid"];
    $channel['cid_list'] = $res["numbers"];
    $channel['cid_number'] = $res["cid_number"];
    $channel['cid_name'] = $res["cid_name"];
    $channel['cid_appexten'] = $res["cid_appexten"];
    $channel['force_cid'] = $res["force_cid"];
    $channel['clir'] = $res["clir"];
    $channelId=putChannel($channel);
    //include account in provider's context
    putAstConfig("extensions.conf", "provider_".$res["provider"], "include", "trunk_".$channelId);
    //get the tech infos
    $techArr=getTechnology($res["technology"]);
    $techRealTime = $techArr[0]["realtime"];
    $techTable    = $techArr[0]["table"];
    $techFile     = $techArr[0]["config_file"];
    //update the incoming context
    if ($techRealTime==1) {
      //$qry="UPDATE $techTable set context='trunk_".$channelId."' WHERE name='".$res["name"]."'";
      $qry="UPDATE $techTable set context='".string2sql("provider_".$res["provider"])."' WHERE name='".string2sql($res["name"])."'";
      $db->Execute($qry);
      //register the provider account
      $contactExt=$res["contact_extension"];
      if(($contactExt!="")&&($contactExt!="s")&&($contactExt!="S")) $contactExt="/".$contactExt;
      else $contactExt="";
      if((isset($res["allow_in"]))&&($res["allow_in"]==1)){
        $commentDesc="";
        $commented=0;
      }else{
        $commentDesc="register disabled by provider definition";
        $commented=1;
      }
      if ($res["technology"]==SIP)  putAstConfig($techFile, "general", "register", $res["username"].":".$res["password"]."@".$res["name"].$contactExt,$commentDesc,$commented);
      if ($res["technology"]==IAX2) putAstConfig($techFile, "general", "register", $res["username"].":".$res["password"]."@".$res["host"].$contactExt,$commentDesc,$commented);
    } 
    else {
      delAstConfig($techFile, $res["name"], "context");
      putAstConfig($techFile, $res["name"], "context", "trunk_".$channelId);
    }
  }
  //if asterisk is ON, reload extensions
  $status=pbxSwitch("status");
  if($status=="ON") sendCommand("reload");
  //return entity id
  return $entity_id;
}

// ---- delProvider(id:int,reload:bool):int ---------------------------------
function delProvider($id,$reload=true) {
  global $db;
  $ret=1;
  //check id and get provider info
  if (!(isset($id) and $id!="")) return 0;
  $providerArr=getProvider($id);
  if (!(is_array($providerArr))) return 0;
  $provider=$providerArr[0];
  if($reload===true){
    // if recursive is true -> delete all provider's account
    $accountArr=$provider["accounts"];
    if(is_array($accountArr)){
      foreach($accountArr as $account){
        $r=delProviderAccount($account["id"]);
        if ($r>0) $ret=$ret and 1; 
        else {
          $ret=$ret and 0; 
          break;
        }
      } 
    }
  }
  //remove the entry from the provider table
  if ($ret>0){
    $qry="DELETE FROM cw_provider WHERE id=$id ";
    $ret=$db->Execute($qry);
  }
  //if asterisk is ON, reload
  if ($ret>0){
    $status=pbxSwitch("status");
    if($status=="ON") sendCommand("reload");
  }
  //return
  return $ret;
}

// ---- delProviderAccount(id:int,reload:int):int -----------------------------
function delProviderAccount($entity_id,$reload=true) {
  global $db;
  //check id and get account info
  if (!(isset($entity_id) and $entity_id!="")) return 0;
  $resArr=getProviderAccount($entity_id,0);
  if (!(is_array($resArr))) return 0;
  $res=$resArr[0];
  //get provider info
  $providerArr=getProvider($res["provider"]);
  if (!(is_array($providerArr))) return 0;
  $provider=$providerArr[0];
  $res["technology"]=$provider["technology"];
  $res["host"]=$provider["host"];
  //get the tech infos
  $techArr=getTechnology($res["technology"]);
  $techRealTime = $techArr[0]["realtime"];
  $techTable    = $techArr[0]["table"];
  $techFile     = $techArr[0]["config_file"];
  //get contact extension
  $contactExt=$res["contact_extension"];
  if(($contactExt!="")&&($contactExt!="s")&&($contactExt!="S")) $contactExt="/".$contactExt;
  else $contactExt="";
  //remove client specific options
  $ret=delEntityOption($entity_id,$res["technology"]);
  //delete the Channel
  $channelId=getChannelFromEntity($entity_id);
  if(($reload===true)&&($channelId!=0)) delChannel($channelId);
  //remove the entry from the resource table
  $qry="DELETE FROM cw_provider_account WHERE id=".$entity_id;
  $db->Execute($qry);
  //delete the registration of the provider
  if ($res["technology"]==SIP)  delAstConfig($techFile, "general", "register", $res["username"].":".$res["password"]."@".$res["name"].$contactExt);
  if ($res["technology"]==IAX2) delAstConfig($techFile, "general", "register", $res["username"].":".$res["password"]."@".$res["host"]);
  //include account from provider's context
  delAstConfig("extensions.conf","provider_".$res["provider"],"include","trunk_".$channelId);
  //remove the resource from the asterisk tables
  $ret=delEntity($entity_id);
  //if asterisk is ON, reload extensions
  if ($reload==1) {
    $status=pbxSwitch("status");
    if($status=="ON") sendCommand("reload");
  }
  return $ret;
}

//******************************************************************************
//******************               CHANNEL                  ********************
//******************************************************************************

// ---- getTechnology(id:int):Technology[] -------------------------------

function getTechnology($id) {
  global $db;
  if ($id!="") $condition=" WHERE id=$id ";
  $qry="SELECT * FROM cw_technology $condition";
  $res=$db->Execute($qry);
  while ($arr=$res->FetchRow()) {
    $ret[]=$arr;
  }
  return $ret;
}

// ---- getChannel(id:int, technology:int):ChannelArray ------------------------
function getChannel($id=0,$technology=0) {
  global $db;
  //get the technology name and compute the Channel name
  if ($id!="") $condition=" WHERE id=$id ";
  else if ($technology!="") $condition=" WHERE technology=$technology ";
  $qry="SELECT * FROM cw_channel ".$condition." ORDER BY `order`";
  $res=$db->Execute($qry);
  while($arr=$res->FetchRow()){
    foreach($arr as $field=>$value) $v[$field]=$value;
    if($v["msns"]!="")  $v["msns"]=split("\|",$v["msns"]); else $v["msns"]=array();
    if($v["cid_list"]!="") $v["cid_list"]=split("\|",$v["cid_list"]); else $v["cid_list"]=array();
    $ret[]=$v;
  }
  return $ret;
}

// ---- getTrunk(id:int, technology:int):ChannelArray -----------------
function getTrunk($id=0,$technology=0) {
  global $db;
  //get the technology name and compute the Channel name
  $condition="WHERE trunk=1";
  if ($id!="") $condition.=" AND id=$id ";
  else if ($technology!="") $condition.=" AND technology=$technology ";
  $qry="SELECT * FROM cw_channel ".$condition." ORDER BY `order`";
  $res=$db->Execute($qry);
  while ($arr=$res->FetchRow()) {
    foreach($arr as $field=>$value) $v[$field]=$value;
    $v["msns"]=split("\|",$v["msns"]);
    $v["cid_list"]=split("\|",$v["cid_list"]);
    $ret[]=$v;
  }
  return $ret;
}

// ---- getChannelFromEntity(id_entity:int):id -----------------
//private
function getChannelFromEntity($id_entity) {
  global $db;
  $qry="SELECT * FROM cw_channel WHERE `key`=$id_entity";
  $res=$db->Execute($qry);
  if ($res->RecordCount()>0) {
    $arr=$res->FetchRow();
    $ret=$arr["id"];
  } else $ret=0;
  return $ret;
}

// ---- moveTrunk(id:int, direction: int):int ----------------------------------
// (Direction=1 : up  |  Direction=2: down) 
function moveTrunk($id,$direction=1,$top=0) {
  global $db;
  //if top!=0 calculate rounds
  if(($top==1)and($direction==1)){
    //retrieve the current order number
    $qry="SELECT `order` FROM cw_channel WHERE id='$id'";
    $res=$db->Execute($qry);
    if($res!==false){
      $arr = $res->FetchRow();
      $orderFrom=$arr["order"];
      //count rounds
  		$qry="SELECT count(*) as count_trunk FROM cw_channel WHERE `order` < $orderFrom and trunk=1";
      $res=$db->Execute($qry);
      if($res!==false){
        $arr=$res->FetchRow();
        $rounds=$arr["count_trunk"];
      }else return 0;
    }else return 0;
  } else if(($top==1)and($direction==2)){
    //retrieve the current order number
    $qry="SELECT `order` FROM cw_channel WHERE id='$id'";
    $res=$db->Execute($qry);
    if($res!==false){
      $arr = $res->FetchRow();
      $orderFrom=$arr["order"];
      //count rounds
      $qry="SELECT count(*) as count_trunk FROM cw_channel WHERE `order` > $orderFrom and trunk=1";
      $res=$db->Execute($qry);
      if($res!==false){
        $arr=$res->FetchRow();
        $rounds=$arr["count_trunk"];
      }else return 0;
    }else return 0;
  } 
  else $rounds=1;
  //move trunk
  $qry="SELECT `order` FROM cw_channel WHERE id='$id'";
  $res=$db->Execute($qry);
  if($res!==false){
    $arr = $res->FetchRow();
    $idFrom=$id;
    $orderFrom=$arr["order"];
    for($i=0;$i<$rounds;$i++){
      //calculate the new positions
      if ($direction==1) {
        $qry="SELECT `order`,id FROM cw_channel WHERE `order` < $orderFrom and trunk=1 ORDER BY `order` DESC";
        $res=$db->Execute($qry);
        $arr = $res->FetchRow();
        $idTo=$arr["id"];
        $orderTo=$arr["order"];
      } else if ($direction==2) {
        $qry="SELECT `order`,id FROM cw_channel WHERE `order` > $orderFrom and trunk=1 ORDER BY `order`";
        $res=$db->Execute($qry);
        $arr = $res->FetchRow();
        $idTo=$arr["id"];
        $orderTo=$arr["order"];
      }
      if (($idFrom=="") or ($idTo=="")) return 0;
      //update trunks table
      $res=$db->Execute("UPDATE cw_channel SET `order`=$orderTo WHERE id=$idFrom");
      $res=$db->Execute("UPDATE cw_channel SET `order`=$orderFrom WHERE id=$idTo");
      //refresh orderFrom
      $orderFrom=$orderTo;
    }
  }
  //refresh the general global variable
  generateGlobalVar();
  //if asterisk is ON, reload extensions
  $status=pbxSwitch("status");
  if($status=="ON") sendCommand("extensions reload");
  //return  
  return 1;
}

// ---- putChannel(Channel:Channel):int ---------------------------------------
function putChannel($channel) {
  global $db;
  $technology=$channel["technology"];
  $resource=$channel["resource"];
  $msns=$channel["msns"];
  $did=$channel["did"];
  $key=$channel["key"];
  $rule=$channel["rule"];
  $speedDial=$channel["speeddial"];
  $order=$channel["order"];
  $trunk=$channel["trunk"];
  $enable_cid=$channel["enable_cid"];
  $cid_list=$channel["cid_list"];
  $cid_number=$channel["cid_number"];
  $cid_name=$channel["cid_name"];
  $cid_appexten=$channel["cid_appexten"];
  $force_cid=$channel["force_cid"];
  $clir=$channel["clir"];
  if ($key=="") $key="0";
  if ($did=="") $did="0";
  if ($order=="") $order="0";
  if ($trunk=="") $trunk="0";
  if ($rule=="")  $rule="0";
  if ($enable_cid=="") $enable_cid="0";
  if ($cid_appexten=="") $cid_appexten="0";
  if ($force_cid=="") $force_cid="0";
  if ($clir=="")  $clir="0";
  //if already exists, retrieve information
  if(isset($channel["id"]) and $channel["id"]!="") {
    $oldChannel=getChannel($channel["id"],0);
    $oldSpeedDial=$oldChannel[0]["speeddial"];
  }
  //check speeddial (must be unique)
  if(!((isset($channel["id"]))and($channel["id"]!="")and($speedDial==$oldSpeedDial))) {
    $allext=getExtension(0);
    if(is_array($allext)){
      foreach($allext as $e)
        if($speedDial==$e["extension"]) return 0;
    }
  }
  //if already exists, delete it
  if((isset($channel["id"]))and($channel["id"]!="")){
    delChannel($channel["id"],false);
    $entity["id"]=$channel["id"];
  }
  //get the technology name and compute the Channel name
  $qry="SELECT * FROM cw_technology WHERE id=".$technology;
  $res=$db->Execute($qry);
  $arr=$res->FetchRow();
  $techName=$arr["name"];
  $channelName=$techName."/".$resource;
  //implode the phone number listening in
  $msnsString=msns2string($msns);
  $cid_listString=msns2string($cid_list);
  //create a new entity
  $entity["type"]=CHANNEL;
  $entity_id=putEntity($entity);
  if(is_object($entity_id) or $entity_id==0) return 0;
  //check speeddial
  if($trunk==1){
    if($speedDial==""){
      $speedDial=getNextSpeedDial();
      if($speedDial==0) return 0;
    }else $speedDial=$speedDial."*";
  }else $speedDial="";
  //check channel's order
  if($order==0 or $order=="") {
    $qry="SELECT MAX(`order`) as last FROM cw_channel";
    $res=$db->Execute($qry);
    $orderArr=$res->FetchRow();
    $order=$orderArr["last"]+1;
  }
  //insert the Channel in the database
  $qry="INSERT INTO cw_channel (`id`,`name`,`technology`,`key`,`msns`,`did`,`rule`,`speeddial`,`order`,`trunk`,`enable_cid`,`cid_list`,`cid_number`,`cid_name`,`cid_appexten`,`force_cid`,`clir`) ";
  $qry.="VALUES ($entity_id,'".string2sql($channelName)."',$technology,$key,'".string2sql($msnsString)."',$did,$rule,";
  $qry.="'".string2sql($speedDial)."',$order,$trunk,$enable_cid,'".string2sql($cid_listString)."','".string2sql($cid_number)."',";
  $qry.="'".string2sql($cid_name)."',$cid_appexten,$force_cid,$clir)";
  $res=$db->Execute($qry);
  if($trunk==1){
    //write the INCOMING context
    $context="trunk_".$entity_id;
    putAstConfig("extensions.conf", $context, "", "", "$channelName Channel- Incoming context",1);
    // DID ENABLED: extract the base number (i.e. if we have a range like 123450-123499, the base number is 1234)
    if ($did!=0) {
      $baseNumber=extractBaseNumber($msnsString);
      putAstConfig("extensions.conf",$context,"exten","$baseNumber,1,NoOp(Incoming-$baseNumber:$context CallerID:\${CALLERID(all)} - Calling:\${EXTEN})");
      putAstConfig("extensions.conf",$context,"exten","$baseNumber,n,AGI(incoming.php,answered=\${EXTEN}&channel=$entity_id&rule=$rule&uniqueid=\${UNIQUEID})");
      putAstConfig("extensions.conf",$context,"exten","_$baseNumber.,1,NoOp(Incoming-$baseNumber:$context CallerID:\${CALLERID(all)} - Calling:\${EXTEN})");
      putAstConfig("extensions.conf",$context,"exten","_$baseNumber.,n,AGI(incoming.php,answered=\${EXTEN}&channel=$entity_id&rule=$rule&uniqueid=\${UNIQUEID})");
    } else {
    // DID DISABLED - list all the available numbers
      $numbers=split("\|",$msnsString);
      if (is_array($numbers))
      foreach($numbers as $n) {
        if ($n!="") {
          putAstConfig("extensions.conf",$context,"exten","$n,1,NoOp(Incoming-$n:$context CallerID:\${CALLERID(all)} - Calling:\${EXTEN})");
          putAstConfig("extensions.conf",$context,"exten","$n,n,AGI(incoming.php,answered=$n&channel=$entity_id&rule=$rule&uniqueid=\${UNIQUEID})");
        }
      }
    }
    putAstConfig("extensions.conf",$context,"exten","s,1,NoOp(Incoming-s. CallerID:\${CALLERID(all)} - Calling:\${EXTEN})");
    putAstConfig("extensions.conf",$context,"exten","s,n,AGI(incoming.php,answered=\${EXTEN}&channel=$entity_id&rule=$rule&uniqueid=\${UNIQUEID})");
    //if ($did!=0) putAstConfig("extensions.conf",$context,"exten","s,1,AGI(dial.php,act=did&rule=".$did."&extension=)");
    putAstConfig("extensions.conf",$context,"exten","t,1,Hangup");
    //write the OUTGOING context
    $context="trunk_out_".$entity_id;
    if ($channel["key"]!="") $metaGroup=getMetaGroupFromEntity($channel["key"]);
    else $metaGroup=GROUP_OF_RESOURCE;
    putAstConfig("extensions.conf", $context, "", "", "$channelName Channel- Outgoing context",1);
    putAstConfig("extensions.conf",$context,"exten","_".$speedDial.".,1,AGI(dial.php,entity=".$entity_id."&group=".GROUP_OF_RESOURCE."&extension=".$speedDial.")");
    if ($metaGroup==GROUP_OF_OFFICE)
      putAstConfig("extensions.conf",$context,"exten",$speedDial.",1,AGI(dial.php,entity=".$key."&group=".$metaGroup."&extension=".$speedDial.")");
    addEntityToGroup($entity_id,array());
    //insert the speeddial in cw_extension
    $entry=array();
    $entry["id"]=0;
    $entry["entity_id"]=$entity_id;
    $entry["extension"]=$speedDial;
    $res=putExtension($entry);
  }
  //regenerate globals var
  generateGlobalVar();
  //Prune client Cid settings if they don't link a valid channel number
  if(isset($channel["id"]) and $channel["id"]!="") { 
  	pruneCidClient($channel["id"],$cid_list);
  }
  //if asterisk is ON, reload extensions
  if(($key=="")or($key=="0")){
    $status=pbxSwitch("status");
    if($status=="ON") sendCommand("extensions reload");
  }
  //return
  return $entity_id;
}

// ---- delChannel(id:int):int ------------------------------------------------
function delChannel($id, $reload=true) {
  global $db;
  $channel=getChannel($id,0);
  $extension=$channel[0]["speeddial"];
  //delete from cw_channel
  $qry="DELETE FROM `cw_channel` WHERE `id`= $id";
  $res=$db->Execute($qry);
  //delete the Channel from the ast_config and extensions_table
  $context="trunk_".$id;
  $res=delAstConfig("extensions.conf",$context,"%");
  if ($id>0) $db->Execute("DELETE FROM extensions_table WHERE context='".string2sql($context)."'");
  //delete the channel_out from the ast_config and extensions_table
  $context="trunk_out_".$id;
  $res=delAstConfig("extensions.conf",$context,"%");
  if ($id>0) $db->Execute("DELETE FROM extensions_table WHERE context='".string2sql($context)."'");
  //remove the resource from the asterisk tables
  removeEntityFromGroup($id);
  //delete all channel's cid settings in cw_cid 
  if($reload===true){ 
    delCid($id,0);
  }
  //regenerate globals var
  generateGlobalVar();
  //delete from cw_extension
  $ret=delExtensionByExtension($extension);
  //if asterisk is ON, reload extensions
  if ($reload===true){
    $status=pbxSwitch("status");
    if($status=="ON") sendCommand("extensions reload");
  } 
  // return value
  return 1;
}


//******************************************************************************
//******************               PHONENUMBERS                  ***************
//******************************************************************************

// ---- getPhoneNumber(id:int):phonenumber[] -----------------------------------
function getPhoneNumber($id) {
  global $db;
  if ($id!="") $condition=" WHERE id=$id ";
  $qry="SELECT * FROM cw_number $condition ORDER BY name";
  $res=$db->Execute($qry);
  while ($v=$res->FetchRow()) { 
    //extract the numbers if many classes are defined
    if($v["number"]!="") $v["number"]=split("\|",$v["number"]);
    else $v["number"]=array();
    //retrieve the client groups
    $qry="SELECT * FROM cw_group_entity WHERE entity_id=".$v["id"];
    $resg=$db->Execute($qry);
    while ($arrg=$resg->FetchRow()) {
      $v["groups"][]=$arrg["group_id"];
    }
    $ret[]=$v;
  }
  // return
  return $ret;
}

// ---- putPhoneNumber(number:PhoneNumber):int ---------------------------------
function putPhoneNumber($number) {
  global $db, $outgoing_prefix;

  $ret=1;
  $entity=array();
  
  //if the phonenumber already exists, delete it
  if (isset($number["id"]) and $number["id"]!="") {
    delPhoneNumber($number["id"]);
    $entity["id"]=$number["id"];
  }

  //create a new entity
  $entity["type"]=PHONENUMBER;
  $entity_id=putEntity($entity);
  if (is_object($entity_id) or $entity_id==0) return 0;
  
  //insert the phonenumber credentials
  $name=$number['name'];
  $emergency=$number['emergency'];
  $pn=implode("|",$number["number"]);
  $qry="INSERT INTO cw_number (id,name,number) ";
  $qry.="VALUES ($entity_id,'".string2sql($name)."','".string2sql($pn)."')";
  $res=$db->Execute($qry);
  if ($res===false) $ret=$ret and 0; else $ret=$ret and 1;
  
  //insert the extensions in the extensions_table
  $context=$number["name"];
  foreach ($number["number"] as $n) {
    $n=str_replace("_","_".$outgoing_prefix,$n);
    putAstConfig("extensions.conf", $context, "exten", "$n,1,AGI(dial.php,entity=$entity_id&group=".GROUP_OF_PHONENUMBER."&extension=\${EXTEN})");
  }
   
  //insert the extensions
  $res=addEntityToGroup($entity_id, $number["groups"]);
  if ($res===false) $ret=$ret and 0; else $ret=$ret and 1;

  //return value
  if ($ret==1) $ret=$entity_id; else $ret=0;

  //if asterisk is ON, reload extensions
  $status=pbxSwitch("status");
  if($status=="ON") sendCommand("reload");
  
  return $ret;
}

// ---- delPhoneNumber(id:int):int ---------------------------------------------

function delPhoneNumber($entity_id) {
  global $db;

  //retrieve the tech type from the client
  $qry="SELECT * FROM cw_number WHERE id=$entity_id";
  $res=$db->Execute($qry);
  $arr=$res->FetchRow();
  $name=$arr["name"];
  
  if ($name!="") {
    //remove the entry from the ast_config
    $res=delAstConfig("extensions.conf",$name);
  
    //delete the extensions from the extensions_table
    $db->Execute("DELETE FROM extensions_table WHERE context='".string2sql($name)."'");

    //remove all the client inclusions    
    if (trim($name)!="") $res=delAstConfig("extensions.conf","%","include",$name);
  }
  
  //remove the client from the asterisk tables and groups
  $ret=removeEntityFromGroup($entity_id);

  //remove the entity
  $ret=delEntity($entity_id);


  //cancello il client
  $qry="DELETE FROM cw_number WHERE id=".$entity_id;
  $db->Execute($qry);
  
  return $ret;
}

//******************************************************************************
//******************               GROUP                    ********************
//******************************************************************************

// ---- getGroup(id:int,type:int):Group[] --------------------------------------
/**
 * Get Group by id and type. 
 *
 * Get all groups of a given type if id is not defined
 * Get all groups of all types if id and type is not defined
 *
 * @param integer groupID. If none specified, then all groups of the given type  are returned
 * @param integer Type of group (extensions, numbers etc.). If none specified, then all types depending on id are returned
 * @return array group[] using the database record structure
 * @see constants.php
 */

function getGroup($id,$type=0) {
  global $db;
  $count=0;
  if ($type!=0) $condition="WHERE type=$type ";
  if ($id!="") $condition="WHERE id=$id ";
  $qry="SELECT * FROM cw_group $condition ORDER BY type, name";
  $res=$db->Execute($qry);
  while ($arr=$res->FetchRow()) { 
    $group_id=$arr["id"];

    //retrieve the entity array
    unset($entity);
    $qry="SELECT entity_id FROM cw_group_entity WHERE group_id=$group_id";
    $res2=$db->Execute($qry);
    while ($arr2=$res2->FetchRow()) $entity[]=$arr2["entity_id"];
    $arr["entity"]=$entity;

    $ret[]=$arr;
  }
  return $ret;
}

// ---- putGroup(group:Group):int ----------------------------------------------

function putGroup($group) {
  global $db;

  //go to the alterGroup function
  if (isset($group["id"]) and $group["id"]!="") {
    $group_id=$group["id"];
    //remove the group
    delGroup($group_id);
    $id_field="`id`,";
    $id_value=$group_id.", ";
  }

  $ret=1;
  $name=$group["name"];
  $type=$group["type"];
  $metagroup=$group["metagroup"];
  if ($metagroup==0) $metagroup="0";
  $qry="INSERT INTO cw_group ($id_field `name`,`type`,`metagroup`) ";
  $qry.="VALUES ($id_value '".string2sql($name)."',$type,$metagroup)";
  $res=$db->Execute($qry);
  if ($res===false) return new soap_fault('Server','','Group creation error, mysql INSERT command failed'); 
  else if (!isset($group_id)) $group_id=$db->Insert_ID();

  //insert the group into Asterisk
  if (is_array($group["entity"]))
  foreach ($group["entity"] as $e) {
    addEntityToGroup($e,array($group_id));        
  }

  //return value
  if ($ret>0) $ret=$group_id;

  //if asterisk is ON, reload extensions
  $status=pbxSwitch("status");
  if($status=="ON") sendCommand("reload");
  
  return $ret;
}

// ---- delGroup(id:int):int --------------------------------------------------

function delGroup($id) {
  global $db;
  
  //retrieve the group name
  $g=getGroup($id);
  $name=$g[0]["name"];

  $qry="DELETE FROM cw_group WHERE id=$id";
  $res=$db->Execute($qry);
  if ($res===false) return new soap_fault('Server','','Group remove error, mysql DELETE command failed');

  $qry="DELETE FROM cw_group_entity WHERE group_id=$id";
  $res=$db->Execute($qry);
  if ($res===false) return new soap_fault('Server','','Group-entity remove error, mysql DELETE command failed');

  //remove the group related entry in the ast_config table
  if (trim($name)!="") {
    $res=delAstConfig("extensions.conf",$name);
    $res=delAstConfig("extensions.conf","%","include",$name);
  }
    
  return 1;
}

//******************************************************************************
//******************             SANDBOX ACCESS            *********************
//******************************************************************************

// ---- getFileFromSandbox(path:string):base64Binary  --------------------------
function getFileFromSandbox($path){
  global $voiceoneWSDocumentRoot;
  // Encode the file ready to send it off
  $file=$voiceoneWSDocumentRoot."/sandbox".$path;
  $handle = fopen($file,"rb");
  $file_content = fread($handle,filesize($file));
  fclose($handle);
  $encoded = base64_encode($file_content);
  $memoryInUse=memory_get_usage();
  return $encoded; 
}

//******************************************************************************
//******************               ISDN CARD               *********************
//******************************************************************************

// MOVED IN ISDN MODULE

//******************************************************************************
//******************               OPTIONS                 *********************
//******************************************************************************

// ---- getOptionByName(name:string,category:string):Option[] -----------------

function getOptionByName($name,$category) {
  global $db;
  $count=0;
  $condition="WHERE name='".string2sql($name)."' and category='".string2sql($category)."' ";
  $qry="SELECT * FROM cw_option $condition ORDER BY category";
  $res=$db->Execute($qry);
  while ($arr=$res->FetchRow()) $ret[]=$arr;
  return $ret;
}

// ---- getConfOption(id:int,category:string):Option[] -----------------------------------------------

function getConfOption($id,$category="",$section="") {
  global $db;
  $count=0;
  if ($id!="") $condition="WHERE id=$id ";
  else if ($category!="") {
    $condition="WHERE category='".string2sql($category)."' ";
		if (($section!="")&&($section==SECTION_GENERAL)) $condition.="AND general_section=1 ";
		else if (($section!="")&&($section==SECTION_DEFAULT)) $condition.="AND default_section=1 ";
	}
  $qry="SELECT * FROM cw_option $condition ORDER BY category";
  $res=$db->Execute($qry);
  while ($arr=$res->FetchRow()) $ret[]=$arr;
  return $ret;
}

// ---- putOption(tech:int, options:AssociativeArray[]):int --------------------
//use it for the general options

function putOption($tech,$options=null,$section="",$reload=true) {
  global $db;
  //get the tech infos
  $techArr=getTechnology($tech);  
  $techName=$techArr[0]["name"];
  $techGeneralContext=$techArr[0]["general_context"];
  //get all the options
  $allOptionsArr=getConfOption(0,$techName,$section);
  //get the custom options
  if (is_array($options))
  foreach ($options as $o) {
    $optionsArr[$o["key"]]=$o["value"];
  }
  //cycle between options and write the new ones
  if (is_array($allOptionsArr)){
	  if (is_array($optionsArr)){
      foreach ($allOptionsArr as $i=>$o) {
        $option_id=$o["id"];
        $value=string2sql($o["value"]); 
        if (@array_key_exists($option_id,$optionsArr)) {
          $allOptionsArr[$i]["commented"]="0";
          $allOptionsArr[$i]["value"]=$optionsArr[$option_id];
          $commented="0";
          $value=$optionsArr[$option_id];
        } else {
          $allOptionsArr[$i]["commented"]="1";      
          $commented="1";
        }
        $qry="UPDATE cw_option set value='".string2sql($value)."', commented=$commented WHERE id=$option_id";
        $db->Execute($qry); 
  		}
		} else { //passed an empty options array
  	  foreach ($allOptionsArr as $i=>$o) {
        $option_id=$o["id"];
        $value=string2sql($o["value"]);
  			$allOptionsArr[$i]["commented"]="1";      
        $commented="1";
  			$qry="UPDATE cw_option set value='".string2sql($value)."', commented=$commented WHERE id=$option_id";
        $db->Execute($qry);
      }
		} 
  }
  //write the config file
  $ret=putOptionInAstConfig($tech,$allOptionsArr,$reload);
  //return value
  return $ret;
}

// ---- putOptionInAstConfig(tech:int, options:AssociativeArray[]):int ---------
function putOptionInAstConfig($tech,$allOptionsArr,$reload=true) {
  global $db;
  //get the tech infos
  $techArr=getTechnology($tech);  
  $techName=$techArr[0]["name"];
  $techGeneralContext=$techArr[0]["general_context"];
  //get all the options
  if(!(is_array($allOptionsArr))) $allOptionsArr=getConfOption(0,$techName);
  //write the config file
  $config_file=$techArr[0]["config_file"];
  if (is_array($allOptionsArr))
  foreach ($allOptionsArr as $i=>$o) {
    if($o["value"]=="") $value=$o["default"]; else $value=$o["value"];
    if($o["general_section"]==1) $context=$techGeneralContext; 
    if($o["general_section"]==0 and $tech==MISDN and $o["default_section"]==1) $context="default";
    if($o["general_section"]==0 and $o["default_section"]==0) continue;
    delAstConfig($config_file, $context, $o["name"], "");
    if(($context==$techGeneralContext)&&($o["name"]=="context")) continue; // DON'T WRITE "context = value" in tecnologies general context
    if($o["commented"]==0){ 
      putAstConfig($config_file, $context, $o["name"], $value, "", 0, "");
    }
    if($tech==ZAP) optimizeAstConfig($tech);
  }
  //if asterisk is ON, reload extensions
  if ($reload===true){
    $status=pbxSwitch("status");
    if($status=="ON") sendCommand("reload");
  }
  //return value 
  return 1;
}  
  
// ---- getEntityOption(entity_id:int):int ----
// private

function getEntityOption($entity_id) {
  global $db;
  $ret=Array();
  
  //retrieve the client specific options
  $qry="SELECT * FROM cw_option_entity  WHERE entity_id=$entity_id";
  $resOpt=$db->Execute($qry);
  while ($arr=$resOpt->FetchRow()) {
    $tmpArr["key"]=$arr["option_id"];
    $tmpArr["value"]=$arr["value"];
    $ret[]=$tmpArr;
  }      
  return $ret;
}


// ---- putEntityOption(options:AssociativeArray, tech:int, entity_id:int, otherOptions:stringArray):int ----
// private
function putEntityOption($options,$tech,$entity_id,$otherOptions) {
  global $db,$keyName;
  
  //get the tech infos
  $techArr=getTechnology($tech);  
  $techName=$techArr[0]["name"];
  $techVoip=$techArr[0]["voip"];
  $techRealTime=$techArr[0]["realtime"];
  $techConfigFile=$techArr[0]["config_file"];
  $techGeneralContext=$techArr[0]["general_context"];
  
  //get the entity type
  $entityArr=getEntity($entity_id);  
  $entityType=$entityArr[0]["type"];

  //get all the options
  $allOptionsArr=getConfOption(0,$techName,0);

  //cycle between options
  if(is_array($options)){
    foreach($options as $i=>$o) {
      $option_id=$o["key"];
      $value=string2sql($o["value"]);
      
      //Retrieve the option name
      $qry="SELECT name,type FROM cw_option WHERE id=$option_id";
      $res=$db->Execute($qry);
      $arr=$res->FetchRow();
      $options[$i]["name"]=$arr["name"];
      $options[$i]["type"]=$arr["type"];
      
      //insert/update the option value in the cw_option_entity table
      $qry="SELECT * FROM cw_option_entity WHERE option_id=$option_id AND entity_id=$entity_id";
      $res=$db->Execute($qry);
      if ($res->RecordCount()==0)
        $qry="INSERT INTO cw_option_entity (option_id,entity_id,value) VALUES ($option_id,$entity_id,'".$value."')";
      else 
        $qry="UPDATE cw_option_entity  set value='".$value."' WHERE option_id=$option_id AND entity_id=$entity_id";
      $db->Execute($qry); 
    }
  }
  //get the context name
  $context=getEntityName($entity_id);
  if($techRealTime==1){
    //if ($entityType==OFFICE) $options[]=array("name"=>"name", "value"=>$otherOptions["username_local"]);
    $options[]=array("name"=>"name", "value"=>$context);
  }
  //SIP & IAX
  if(($tech==SIP or $tech==IAX2) and $entityType==EXTENSION) {
    $options[]=array("name"=>"secret",    "value"=>$otherOptions["password"]);
    $options[]=array("name"=>"username",  "value"=>$context);
    if(!array_key_exists_recursive("callerid",$options)){  
      $options[]=array("name"=>"callerid",  "value"=>$otherOptions["name"]." ".$otherOptions["surname"]." <".$otherOptions["extension"].">");
    }
    if(!array_key_exists_recursive("host",$options)){
      $options[]=array("name"=>"host",  "value"=>"dynamic");
    }
    // Fix MWI until we have a flag MWI yes/no in voicemail setup
    if(!array_key_exists_recursive("mailbox",$options)){
      $options[]=array("name"=>"mailbox",  "value"=>$otherOptions["voicemail"]["mailbox"]);
    }
    // Fix qualify=yes for iax extensions
    if($tech==IAX2){
      if(!array_key_exists_recursive("qualify",$options))  
        $options[]=array("name"=>"qualify",  "value"=>"yes");
    }
  }
  //MISDN
  if($tech==MISDN and $entityType==EXTENSION){
    $options[]=array("name"=>"msns",  "value"=>$otherOptions["extension"]);
    if(!array_key_exists_recursive("callerid",$options)){  
      $options[]=array("name"=>"callerid",  "value"=>"\"".$otherOptions["name"]." ".$otherOptions["surname"]."\" <".$otherOptions["extension"].">");
    }
  }
  //ZAP
  if($tech==ZAP){
    $options[]=array("name"=>"signalling",  "value"=>$otherOptions["signalling"]);
    if($entityType==EXTENSION){
      $options[]=array("name"=>"group",  "value"=>"0");
      if(!array_key_exists_recursive("callerid",$options)){  
        $options[]=array("name"=>"callerid",  "value"=>"\"".$otherOptions["name"]." ".$otherOptions["surname"]."\" <".$otherOptions["extension"].">");
      }
      if(!array_key_exists_recursive("mailbox",$options)){
        $options[]=array("name"=>"mailbox",  "value"=>$otherOptions["voicemail"]["mailbox"]);
      }
    }else{
      $options[]=array("name"=>"group",  "value"=>$otherOptions["group"]);
    }
  }
  //PROVIDER ACCOUNT
  if($techVoip==1 and $entityType==PROVIDER_ACCOUNT){
    // This needs to have a flag for CallerId
    if (!array_key_exists_recursive("callerid",$options))  
      $options[]=array("name"=>"callerid",  "value"=>$otherOptions["p_name"]);
    if (!array_key_exists_recursive("fromuser",$options))  
      $options[]=array("name"=>"fromuser",  "value"=>$otherOptions["username"]);
    if (!array_key_exists_recursive("fromdomain",$options))  
      $options[]=array("name"=>"fromdomain",  "value"=>$otherOptions["host"]);
    if (!array_key_exists_recursive("host",$options))  
      $options[]=array("name"=>"host",  "value"=>$otherOptions["host"]);
    if (!array_key_exists_recursive("username",$options))  
      $options[]=array("name"=>"username",  "value"=>$otherOptions["username"]);
    if (!array_key_exists_recursive("secret",$options))  
      $options[]=array("name"=>"secret",  "value"=>$otherOptions["password"]);
    if (!array_key_exists_recursive("port",$options))  
      $options[]=array("name"=>"port",  "value"=>$otherOptions["port"]);
    if (!array_key_exists_recursive("insecure",$options))  
      $options[]=array("name"=>"insecure",  "value"=>"very");
  }
  //OFFICE
  if($entityType==OFFICE){
    //$options["name"]=$otherOptions["username_local"];
    if (!array_key_exists_recursive("callerid",$options))  
      $options[]=array("name"=>"callerid",  "value"=>$otherOptions["name"]);
    if (!array_key_exists_recursive("fromuser",$options))  
      $options[]=array("name"=>"fromuser",  "value"=>$otherOptions["username"]);
    if (!array_key_exists_recursive("fromdomain",$options))  
      $options[]=array("name"=>"fromdomain",  "value"=>$otherOptions["host"]);
    if (!array_key_exists_recursive("host",$options))  
      $options[]=array("name"=>"host",  "value"=>$otherOptions["host"]);
    if (!array_key_exists_recursive("username",$options))  
      $options[]=array("name"=>"username",  "value"=>$otherOptions["username"]);
    if (!array_key_exists_recursive("secret",$options))  
      $options[]=array("name"=>"secret",  "value"=>$otherOptions["password"]);
    if (!array_key_exists_recursive("port",$options))  
      $options[]=array("name"=>"port",  "value"=>$otherOptions["port"]);
    //if (!array_key_exists_recursive("auth",$options))  
    if ($otherOptions["inkey"]!="") {
      $options[]=array("name"=>"auth",  "value"=>"rsa");      
      $options[]=array("name"=>"inkeys",  "value"=>$otherOptions["name"]);      
      $options[]=array("name"=>"outkey",  "value"=>$keyName);      
    } else $options[]=array("name"=>"auth",  "value"=>"plaintext");      
  }
  //case REALTIME
  if ($techArr[0]["realtime"]==1) {
    $table=$techArr[0]["table"];
    foreach ($options as $i=>$o) {
      if(strtoupper($o["value"])=="NULL"){
        $field_list.="`".$o["name"]."`,";
        $value_list.="NULL,";
      }else{
        $field_list.="`".$o["name"]."`,";
        $value_list.="'".string2sql($o["value"])."',";
      }
    }
    $field_list=substr($field_list,0,-1);
    $value_list=substr($value_list,0,-1);
    $qry="INSERT INTO $table ($field_list) VALUES ($value_list)";
    $db->Execute($qry);
  }  
  //case NOT REALTIME
  else{
    $zsection="";
    if($tech==ZAP){ $zsection=$context; $context=$techGeneralContext;}
    foreach ($options as $i=>$o) {
      putAstConfig($techConfigFile, $context, $o["name"], $o["value"], '', '0' , $zsection);
    }
    if($tech==ZAP) optimizeAstConfig($tech);
  }  
  return true;
}


// ---- delEntityOption(id:int):int --------------------------------------------------
// private

function delEntityOption($entity_id, $tech) {
  global $db;

  //get the tech infos
  $techArr      = getTechnology($tech);  
  $techName     = $techArr[0]["name"];
  $techRealTime = $techArr[0]["realtime"];
  $techTable    = $techArr[0]["table"];
  $techFile     = $techArr[0]["config_file"];
  $techGeneralContext=$techArr[0]["general_context"];
  
  //remove options from the table
  $qry="DELETE FROM cw_option_entity WHERE entity_id=$entity_id";
  $res=$db->Execute($qry);
  
  //get the context name
  $context=getEntityName($entity_id);
  if ($context=="") return 0;
  
  //delete from asterisk table REALTIME/STATIC
  if ($techRealTime==1) $db->Execute("DELETE FROM $techTable WHERE name='$context'");
  else{
    $zsection="";
    if($tech==ZAP){
      $zsection=$context;
      $context=$techGeneralContext;
    }
    delAstConfig($techFile, $context, '', '', $zsection);
    if($tech==ZAP) optimizeAstConfig($tech);
  }
  //return
  return 1;
}

//******************************************************************************
//******************               APPLICATIONS             ********************
//******************************************************************************
/**
 * Get application by id or get all applications if id is not defined
 *
 * @param integer applicationID. If none specified, then all applications are returned
 * @return array Application[] using the database record structure  and add groups 
 * @see putApplication
 * @see delApplication
 * @see getApplicationByName
 * @todo fix group export to be xml compliant (do not use numeric tags)
 */

// ---- getApplication(id:int):Application[] -----------------------------------

function getApplication($id=0) {
  global $db;
  $count=0;
  if ($id!="") $condition="WHERE id=$id ";
  $qry="SELECT * FROM cw_application $condition ORDER BY name";
  $res=$db->Execute($qry);

  while ($arr=$res->FetchRow()) {
    //retrieve the client groups
    $arr["groups"]=Array();
    $qry="SELECT * FROM cw_group_entity WHERE entity_id=".$arr["id"];
    $resGrp=$db->Execute($qry);
    while ($arrGrp=$resGrp->FetchRow()) $arr["groups"][]=$arrGrp["group_id"];

    $ret[]=$arr;
  }

  return $ret;
}

/**
 * Get application by name
 *
 * @param string $name
 * @return array Application[] using the database record structure  and add groups 
 * @see putApplication
 * @see delApplication
 * @see getApplication
 * @todo fix group export to be xml compliant (do not use numeric tags)
 */
function getApplicationByName($name) {
  global $db;
  $count=0;
  $qry="SELECT * FROM cw_application WHERE name='".string2sql($name)."' ORDER BY label";
  $res=$db->Execute($qry);
  
  while ($arr=$res->FetchRow()) {
    //retrieve the client groups
    $arr["groups"]=Array();
    $qry="SELECT * FROM cw_group_entity WHERE entity_id=".$arr["id"];
    $resGrp=$db->Execute($qry);
    while ($arrGrp=$resGrp->FetchRow()) $arr["groups"][]=$arrGrp["group_id"];
    $ret[]=$arr;
  }

  return $ret;
}


// ---- putApplication(app:Application, $keepId:Boolean):int -----------------------------------

/**
 * Add an application to the system 
 *
 * If the parameter array contains a value for ['id'] than putApplication tries to update the application and keeps the id
 * @param array $app app:Application
 * @param boolean $keepId default: true=keep Id regardless of the name; false=keep Id only if name matches
 * @return integer $entityId or 0 if failure 
 * @see getApplication
 * @see delApplication
 * @todo FIX BUG in groups / apps / metagroup handling.  disabled group for now.
 */
function putApplication($app, $keepId=true) {
  global $db;
	
  $entity=array();
  $ret=1;

  //if already exists, retrieve information
  if (isset($app["id"]) and $app["id"]!="") {
    $oldApp=getApplication($app["id"]);
    $oldSpeedDial=$oldApp[0]["extension"];
    $agent_id=getAgentFromEntity($app["id"]);
    if($agent_id!=0){
      $agentArr=getAgent($agent_id);
      if((is_array($agentArr))&&(is_array($agentArr[0]))){
      	$agent=$agentArr[0];
      }
    }
  }
  //check speeddial (must be unique)
  if(!((isset($app["id"]))and($app["id"]!="")and($app["extension"]==$oldSpeedDial))) {
    $allext=getExtension(0);
    if(is_array($allext)){
      foreach($allext as $e)
        if($app["extension"]==$e["extension"]) return 0;  
    }
  }

  // Request for Update? 
  // By name or by id?  
  // Update via edit would be by id
  // Update via plugin would be by name
  // Otherwise we would risk to override a complete different entity via a plugin
  // So $keepId should be false if called via putPlugin.
  
  if ((isset($app["id"])) and ($app["id"] != "") and ($keepId == true)) {
    // id is set for new app and must be used
      $entity["id"] = $app["id"];
      delApplication($entity["id"], false);
  } elseif ((isset($app["name"])) and ($app["name"] != "") and ($keepId == false)) {
    // name is set for new app and must be used
    $curApp = getApplicationByName($app["name"]);
    if ($curApp[0]['name'] == $app['name']) {
      // name matches, so update is ok
      $entity["id"] = $curApp[0]['id'];
      delApplication($entity["id"], false);
    }
  }

  //create a new entity
  $entity["type"]=APPLICATION;
  $entity_id=putEntity($entity);
  if (is_object($entity_id) or $entity_id==0) return 0;
  
  //insert the application credentials
  $label=$app["label"];
  if ($app["name"]=="") $name=preg_replace("/[^0-9a-z]/i",'',$app["label"])."_".$entity_id; else $name=$app["name"];
  $description=$app["description"];
  $extension=$app["extension"];
  $code=$app["code"];
  $macro=$app["macro"];
  $parameter=$app["parameter"];
  $groups=$app["groups"];
  $qry="INSERT INTO cw_application (id,name,label,description,extension,code,macro,parameter,groups) ";
  $qry.="VALUES ($entity_id,'".string2sql($name)."','".string2sql($label)."','".string2sql($description)."',";
  $qry.="'".string2sql($extension)."','".string2sql($code)."','".$macro."','".string2sql($parameter)."','".string2sql($groups)."')";
  $r=$db->Execute($qry);
  if ($r===false) $ret=$ret and 0; else $ret=$ret and 1;

  $context="app-$name";
  putAstConfig("extensions.conf", $context, "exten", "$extension,1,AGI(dial.php,entity=$entity_id&group=".GROUP_OF_APPLICATION."&extension=\${EXTEN})");

  //insert the application to groups
  $res=addEntityToGroup($entity_id, $groups);  
  if ($res===false) $ret=$ret and 0; else $ret=$ret and 1;
  //insert the speeddial in cw_extension
  if($ret==1) {
    $entry=array();
    $entry["id"]=0;
    $entry["entity_id"]=$entity_id;
    $entry["extension"]=$extension;
    $res=putExtension($entry);
  }
  if ($res===false) $ret=$ret and 0; else $ret=$ret and 1;
  //get agent linked to application
  if(is_array($agent)){
  	$agent["extension"]=$extension;
    putAgent($agent);
  }
  //return value
  if ($ret==1) $ret=$entity_id; else $ret=0;
  //if asterisk is ON, reload extensions
  $status=pbxSwitch("status");
  if($status=="ON") sendCommand("reload");
  return $ret;
}

// ---- delApplication(id:int):int --------------------------------------------------
/**
 * Remove an application by id from the system
 *
 * If the parameter array contains a value for ['id'] than putApplication tries to update the application and keeps the id
 * @param integer $appId id of application
 * @param boolean $reload flag to indicate wether asterisk should reload the configuration
 * @return integer 1
 * @see getApplication
 * @see delApplication
 */

function delApplication($entity_id,$reload=true) {
  global $db;
    
  //get the entity type
  //$entityArray=getEntity($entity_id);
  //$entity=$entityArray[0];

  //get the application name
  $application=getApplication($entity_id);
  $name="app-".$application[0]["name"];
  $extension=$application[0]["extension"];

  //remove the entry from the ast_config
  $res=delAstConfig("extensions.conf",$name);
  
  //delete the extensions from the extensions_table
  $db->Execute("DELETE FROM extensions_table WHERE context='$name'");

  //remove all the client inclusions    
  if (trim($name)!="") $res=delAstConfig("extensions.conf","%","include",$name);

  //remove the resource from the asterisk tables
  $ret=removeEntityFromGroup($entity_id);

  //remove the entry from the resource table
  $qry="DELETE FROM cw_application WHERE id=".$entity_id;
  $db->Execute($qry);
  
  //remove from cw_extension
  $ret=delExtensionByExtension($extension);
  
  //remove the entity
  $ret=delEntity($entity_id);

  //delete agent
  $agent_id=getAgentFromEntity($entity_id);
  if($agent_id!=0){
  	delAgent($agent_id);
  }
  //reload the extensions
  if ($reload===true) {
    //if asterisk is ON
    $status=pbxSwitch("status");
    if($status=="ON"){
      //$qry="DELETE FROM ast_config WHERE filename='extensions.conf' AND category='app-$name'";
      //$db->Execute($qry);
    
      sendCommand("reload");
      //createAstConfig("extensions.conf");
    }
  }
  
  return 1;
}


//******************************************************************************
//******************               IVR                      ********************
//******************************************************************************


// ---- getIvr(id:int):Ivr[] ---------------------------------------------------
/**
 * Get IVR by id or get all IVRs if id is not defined
 *
 * @param integer ivrID. If none specified, then all IVRs are returned
 * @return array ivr[] using the database record structure
 */
/*
function getIvr($id=0) {
  global $db;
  if ($id!="") $condition="WHERE id=$id ";
  $qry="SELECT * FROM cw_ivr $condition ORDER BY name";
  $res=$db->Execute($qry);
  while ($arr=$res->FetchRow()) $ret[]=$arr;
  return $ret;
}

// ---- putIvr(ivr:Ivr):int ----------------------------------------------------

function putIvr($ivr) {
  global $db;
  $ret=1;

  $node=Array("name"=>$ivr["name"],"parent"=>0,"order"=>0);
  $rootNode=putIvrNode($node);
  
  $name=$ivr["name"];
  $qry = "INSERT INTO cw_ivr (`name`,`rootnode`) VALUES ('".string2sql($name)."',$rootNode)";
  $res=$db->Execute($qry);
  if ($res===false) return new soap_fault('Server','','Ivr creation error, mysql INSERT command failed'); 
  $ivr_id=$db->Insert_ID();

  return $ivr_id;
}

// ---- delIvr(id:int):int --------------------------------------------------

function delIvr($id) {
  global $db;
  
  $qry="DELETE FROM cw_ivr WHERE id=$id";
  $res=$db->Execute($qry);
  if ($res===false) return new soap_fault('Server','','Ivr remove error, mysql DELETE command failed');

  return 1;
}



// ---- getIvrNode(id:int, ivr:int):IvrNode[] -----------------------------------------------

function getIvrNode($id=0,$ivr=0,$parent=0) {
  global $db;

  $count=0;
  $ret=array();

  if ($id==0 AND $ivr==0 AND $parent==0) {
    $qry="SELECT * FROM cw_ivr_node";

  } else if ($ivr!=0) {
    $ivrArr=getIvr($ivr); 
    $rootNode=$ivrArr[0]["rootnode"];

    $qry="SELECT * FROM cw_ivr_node WHERE id=$rootNode";
    $res=$db->Execute($qry);
    $arr=$res->FetchRow(); 
    $ret[]=$arr;

    $qry="SELECT * FROM cw_ivr_node WHERE parent=$rootNode ORDER BY `order`";

  } else if ($parent!=0) {
    $qry="SELECT * FROM cw_ivr_node WHERE parent=$parent ORDER BY `order`";
    
  } else if ($id!=0) {
    $qry="SELECT * FROM cw_ivr_node WHERE id=$id";
  }  else {return ;}

  $res=$db->Execute($qry);
  while ($arr=$res->FetchRow()) { 
    $node_id=$arr["id"];
    $ret[]=$arr;
    $ret=array_merge($ret,getIvrNode(0,0,$node_id));
  }
  return $ret;
}

// ---- putIvrNode(node:IvrNode):int ----------------------------------------------

function putIvrNode($node) {
  global $db;
  
  extract($node);
  
  //delete old node    
  if ($id!="" and $id!="0") {
    //retrieve the current (old) order number
    $qry="SELECT `order`,`parent` FROM cw_ivr_node WHERE id=$id";
    $res=$db->Execute($qry);
    $arr = $res->FetchRow();
    $oldPos=$arr["order"];
    $parent=$arr["parent"];

    delIvrNode($id);
  } else $id="null";

  //if no order is assigned, append as the last node
  if ($order=="0" or $order=="") {
    if ($parent=="") $parent=0;
    $res=$db->Execute("SELECT COUNT(*) as howmuch FROM cw_ivr_node WHERE parent=$parent");
    $arr=$res->FetchRow();
    $order=$arr["howmuch"]+1;
  }

  //check for swap node
  $qry="SELECT * FROM cw_ivr_node WHERE `order`=$order AND `parent`=$parent";
  $res=$db->Execute($qry);
  if ($res->RecordCount()>0) {
    $arr = $res->FetchRow();
    $nodeToSwap=$arr["id"];
    //if no order is assigned, append as the last node
    if ($oldPos=="") {
      if ($parent=="") $parent=0;
      $res=$db->Execute("SELECT COUNT(*) as howmuch FROM cw_ivr_node WHERE parent=$parent");
      $arr=$res->FetchRow();
      $oldPos=$arr["howmuch"]+1;
    }
    $qry="UPDATE cw_ivr_node SET `order`=$oldPos WHERE id=$nodeToSwap";
    $db->Execute($qry);
  }

  //insert the new node
  $qry="INSERT INTO cw_ivr_node (`id`,`name`,`parent`,`order`, `key`, `audio`, `macro`, `parameter`, `timesegment`,  `taudio`, `trepeat`, `iaudio`, `irepeat`) ";
  $qry.="VALUES ($id,'".string2sql($name)."','".$parent."','".$order."','".string2sql($key)."','".string2sql($audio)."','".$macro."',";
  $qry.="'".string2sql($parameter)."','".$timesegment."','".string2sql($taudio)."','".$trepeat."','".string2sql($iaudio)."','".$irepeat."')";
  $res=$db->Execute($qry);

  
  if ($res===false) return new soap_fault('Server','','IVR creation error, mysql INSERT command failed');
  else $node_id=$db->Insert_ID();

  if ($id!="null") $ret=$id; else $ret=$node_id;
  return $ret;
}

// ---- delIvrNode(id:int):int --------------------------------------------------

function delIvrNode($id) {
  global $db;
  
  $qry="DELETE FROM cw_ivr_node WHERE id=$id";
  $res=$db->Execute($qry);
  if ($res===false) return new soap_fault('Server','','Ivr remove error, mysql DELETE command failed');
  return 1;
}

// ---- swapIvrNode(id:int, newpos:int):int --------------------------------------------------
function swapIvrNode($id,$parent,$newPos,$oldPos) {
  global $db;
  
  if ($newPos=="") return;
  if ($oldPos==newPos) return;
 
  //retrieve the current (old) order number
  $qry="SELECT * FROM cw_ivr_node WHERE `order`=$newPos AND `parent`=$parent";
  $res=$db->Execute($qry);
  if ($res->RecordCount()>0) {
    $arr = $res->FetchRow();
    $nodeToSwap=$arr["id"];
    $qry="UPDATE cw_ivr_node SET `order`=$oldPos WHERE id=$nodeToSwap";
    $db->Execute($qry);  
  }
  return;
}


// ---- moveIvrNode(id:int, direction: int):int --------------------------------------------------
// Direction=1 : up
// Direction=2: down

function moveIvrNode($id,$direction=1) {
  global $db;
  
  //retrieve the current order number
  $qry="SELECT `order`,`parent` FROM cw_ivr_node WHERE id=$id";
  $res=$db->Execute($qry);
  $arr = $res->FetchRow();
  $order=$arr["order"];
  $parent=$arr["parent"];
  if ($parent=="") $parent=0;
  

  if ($direction==1 and $order>1) {
    $res=$db->Execute("UPDATE cw_ivr_node SET `order`='$order' WHERE `parent`=$parent AND `order`=".($order-1));
    if ($db->Affected_Rows()>0) $res=$db->Execute("UPDATE cw_ivr_node SET `order`=".($order-1)." WHERE id=$id");
  } else if ($direction==2) {
    $res=$db->Execute("UPDATE cw_ivr_node SET `order`=$order WHERE `parent`=$parent AND `order`=".($order+1));
    if ($db->Affected_Rows()>0) $res=$db->Execute("UPDATE cw_ivr_node SET `order`=".($order+1)." WHERE id=$id");
  }
  if ($res===false) return new soap_fault('Server','','Ivr move error, mysql UPDATE command failed');
  else return 1;

}


// ---- compileIvr($ivr_id:int):int --------------------------------------------

function compileIvr($ivr_id) {
  global $db,$ivrPrefix,$ivrScriptConversionPath;

  //clear the old ivr
  clearIvr($ivr_id);

  //$ret=exec("$ivrScriptConversionPath &",$out);

  //build the new ivr
  _compileIvr($ivr_id);

  //if asterisk is ON, reload extensions
  $status=pbxSwitch("status");
  if($status=="ON") sendCommand("reload");

  return 1;
}  

// ---- clearIvr():int --------------------------------------------------
//private

function clearIvr($ivr_id) {
  global $db,$ivrPrefix;
  
  $qry="DELETE FROM extensions_table WHERE context like '".string2sql($ivrPrefix.$ivr_id)."%'";
  $res=$db->Execute($qry);

  $res=delAstConfig("extensions.conf",$ivrPrefix.$ivr_id."%");

  return 1;
}

// ----    _compileIvr():int     -----------------------------------------------
//private

function _compileIvr($ivr_id,$parent=0) {
  global $db,$ivrPrefix,$ivrStartingDir;

  //retrieve the parent node name (calculate the context)
  $qry="SELECT * FROM cw_ivr_node WHERE `id`=$parent";
  $resp=$db->Execute($qry);
  $arrp=$resp->FetchRow();
  $context=$ivrPrefix.$ivr_id.$arrp["name"];
  
  //set the query for cycling through the children nodes
  if ($parent==0) {
    $i=getIvr($ivr_id);
    $rootNode=$i[0]["rootnode"];
    $qry="SELECT * FROM cw_ivr_node WHERE `id`=$rootNode";
  } else 
    $qry="SELECT * FROM cw_ivr_node WHERE `parent`=$parent ORDER BY `order`";
  
  $playBeep=false;
  $priority=1;
  $res=$db->Execute($qry);
  while ($arr = $res->FetchRow()) {
    $nodeId=$arr["id"];
    $nodeName=$arr["name"];
    $nodeParent=$arr["parent"];
    $nodeAudio=str_replace(" ","",substr($arr["audio"],0,strpos($arr["audio"],".")));
    $nodeIAudio=str_replace(" ","",substr($arr["iaudio"],0,strpos($arr["iaudio"],".")));
    $nodeTAudio=str_replace(" ","",substr($arr["taudio"],0,strpos($arr["taudio"],".")));
    $nodeContext=$ivrPrefix.$ivr_id.$nodeName;
    $nodeKey=$arr["key"];
    $nodeMacro=$arr["macro"];
    $nodeIRepeat=$arr["irepeat"];
    $nodeTRepeat=$arr["trepeat"];
    $nodeParameter=$arr["parameter"];

    //branch or leaf?
    $qry="SELECT * FROM cw_ivr_node WHERE `parent`=$nodeId";
    $resp=$db->Execute($qry);
    if ($resp->RecordCount()>0) $nodeFolder=true;
    else $nodeFolder=false;
    
    //play the audio files
    if ($nodeAudio!="") 
      putAstConfig("extensions.conf", $context, "exten", "s,".($priority++).",Background(".$ivrStartingDir.$nodeAudio.")");

    //insert the extension KEY for jumping inside the branches
    if ($nodeFolder===true) {
      if ($nodeKey=="")
        putAstConfig("extensions.conf", $context, "exten", "s,".($priority++).",Goto($nodeContext|s|1)");
      else 
        putAstConfig("extensions.conf", $context, "exten", "$nodeKey,1,Goto($nodeContext|s|1)");
    }

    //take action
    if ($nodeMacro!=0 and $nodeFolder===false) {
      $macroArr=prepareMacro($nodeMacro,$nodeParameter);
      $macroName=$macroArr[0];
      $macroParam=substr($macroArr[1],1); 
      $macroParam=$macroArr[1];  
      if ($nodeKey=="") 
        putAstConfig("extensions.conf", $context, "exten", "s,".($priority++).",Macro(".$macroName.$macroParam.")");
      else 
        putAstConfig("extensions.conf", $context, "exten", "$nodeKey,1,Macro(".$macroName.$macroParam.")");
    }
      
    //insert the INVALID and TIMEOUT extensions
    if ($nodeFolder===true) {
      $ipriority=1;
      $tpriority=1;
      if ($nodeIAudio!="") 
        putAstConfig("extensions.conf", $nodeContext, "exten", "i,".($ipriority++).",Background(".$ivrStartingDir.$nodeIAudio.")");
      if ($nodeIRepeat==1) 
        putAstConfig("extensions.conf", $nodeContext, "exten", "i,".($ipriority++).",Goto($nodeContext|s|1)");
      if ($nodeTAudio!="") 
        putAstConfig("extensions.conf", $nodeContext, "exten", "t,".($tpriority++).",Background(".$ivrStartingDir.$nodeTAudio.")");
      if ($nodeTRepeat==1) 
        putAstConfig("extensions.conf", $nodeContext, "exten", "t,".($tpriority++).",Goto($nodeContext|s|1)");
    }

    //set the playBeep variable
    if ($nodeKey!="") $playBeep=true;
    
    //recursively create the tree
    if ($nodeFolder===true) _compileIvr($ivr_id,$nodeId);
  }

  //play beep
  if ($playBeep===true)
    putAstConfig("extensions.conf", $context, "exten", "s,".($priority++).",Playback(beep)");
    putAstConfig("extensions.conf", $context, "exten", "s,".($priority++).",WaitExten()");
  
  
  //manage the root node case:
  if ($parent==0) {
    putAstConfig("extensions.conf", $context, "exten", "s,".($priority++).",Hangup");
    putAstConfig("extensions.conf", $context, "exten", "i,1,Goto($context|s|1)");
    putAstConfig("extensions.conf", $context, "exten", "t,1,Goto($context|s|1)");
  }
  
  return;
}
*/
//******************************************************************************
//******************               PLUGIN                   ********************
//******************************************************************************
  
/**
 * Get plugin by id from database. If no id is specified, get an array with all plugins
 *
 * @param integer $id: Plugin Id or "" for all plugins
 * @return array $ret tns:PluginArray with one / all plugins installed on the system or "".
 * @see putPlugin
 * @see delPlugin
 * @see getPluginByName
 * @see getPluginByPackageName
 * @see getPluginByEntity
 * @see getPluginEntities
 */

function getPlugin($id) {
  global $db;
  $ret = array();
  if ($id != "") $condition = " WHERE id=$id ";
  $qry = "SELECT * FROM cw_plugin $condition ";
  $res = $db->Execute($qry);
  while($arr = $res->FetchRow()) {
    foreach($arr as $field=>$value) {
      $v[$field] = $value;
    }
    $ret[] = $v;
  }
  return $ret;
}

/**
 * Get plugin by name from database.
 *
 * @param string $name: Plugin short name i.e "Wake-Up_Call"
 * @return array $ret tns:PluginArray with one plugin or "" if plugin is not installed
 * @see getPlugin
 * @see getPluginByPackageName
 * @see getPluginByEntity
 * @see putPlugin
 * @see getPluginEntities
 */
function getPluginByName($name) {
  global $db;
  $ret = array();
  $qry = "SELECT * FROM cw_plugin WHERE name='".string2sql($name)."'";
  $res = $db->Execute($qry);
  while($arr = $res->FetchRow()) {
    foreach($arr as $field=>$value) {
      $v[$field] = $value;
    }
    $ret[] = $v;
  }
    
  return $ret;
}


/**
 * Get plugin by packageName (=name.version) from database. 
 * 
 * @param string $packageName i.e "Wake-Up_Call.1.10.0"
 * @return array $ret tns:PluginArray with one plugin or "" if plugin is not installed
 * @see getPlugin
 * @see getPluginByName
 * @see getPluginByEntity
 * @see putPlugin
 * @see delPlugin
 * @see getPluginEntities
 */
function getPluginByPackageName($packageName) {
  global $db;
  $ret = array();
  $qry = "SELECT * FROM cw_plugin WHERE package_name='".string2sql($packageName)."'";
  $res = $db->Execute($qry);
  while($arr = $res->FetchRow()) {
    foreach($arr as $field=>$value) {
      $v[$field] = $value;
    }
    $ret[] = $v;
  }
  
  return $ret;
}
  
/**
 * Get plugin entities for an activated plugin from database. If no id is specified, get array with entities for all plugins
 *
 * @param integer $id: PluginId or "" for all plugins
 * @return array $ret tns:PluginEntityArray or "" if plugin is not installed
 * @see getPlugin
 * @see getPluginByName
 * @see getPluginByPackageName
 * @see getPluginByEntity
 * @see putPlugin
 * @see delPlugin 
 */
function getPluginEntities($id) {
  global $db;
  $ret = array();
  if ($id != "") { $condition=" WHERE plugin_id = $id"; }
  $qry = "SELECT * FROM cw_plugin_entity $condition";
  $res = $db->Execute($qry);
  while($arr = $res->FetchRow()) {
    foreach($arr as $field=>$value) {
      $v[$field] = $value;
    }
    $ret[] = $v;
  }
    
  return $ret;
}



/**
 * Get plugin by vo-object (entity). If more than one plugin uses that entity, a list of plugins is returned.
 *
 * @param string $type: Entity type as string like "application", "macro" or "queue". String because entities do not have unique id's
 * @param integer $id: Entity Id
 * @return array $ret tns:PluginArray with plugins that uses the specified entity or ""
 * @see getPlugin
 * @see getPluginByName
 * @see getPluginByPackageName
 * @see putPlugin
 * @see delPlugin 
 */
function getPluginbyEntity($eType, $eId) {
  global $db;
  $ret = array();
  // Use new Syntax that is ANSI-92 conform
  $qry = "SELECT * FROM cw_plugin as p INNER JOIN cw_plugin_entity AS e ON p.id = e.plugin_id WHERE e.entity_type = '".string2sql($eType)."' and e.entity_id = $eId";
  $res = $db->Execute($qry);
  while ($arr = $res->FetchRow()) {
    foreach($arr as $field=>$value) {
      $v[$field] = $value;
    }
    $ret[] = $v;
  }
  return $ret;
  
}
 
 
// ---- putPlugin(xmlpli:string,xmlpld:string):int ---------------------------

/**
 * Insert plugin from XML String to the system
 * 
 * Fixes automatically references based on id's between vo-objects like application->macro
 * Note: So far, the plugin support is limited to macros, applications and queues
 * @param string $pli XML of plugin information
 * @param string $pld XML of plugin data (plugin objectcs)
 * @return integer 1=ok 0 or less failure
 * @see delPlugin
 * @see getPluginByName
 * @see getPluginByPackageName
 * @todo handle errors, updates and return errorcode. Support more objects. 
 */
function putPlugin($pli, $pld) {
  
  global $db;
  
  // putplugin works in the following steps
  // - validate xml parameter
  // - read plugin data, put vo-objects in database etc.
  // - fix references based on id's between vo-objects. I.e. app uses macro with id=3
  // - update database with plugin info    
     
  //
  // get plugin information.  
  //
  $xmlArr=xml2array($pli);
 //errArr($xmlArr);
   
  // to be valid, root node must be <plugininfo>. otherwise exit
  if ($xmlArr[0]['name'] != 'plugininfo') {
    //error_log("missing valid plugininfo. no valid plugin");
    return 0;
  }
  
   
  // read plugin info into array.
  foreach ($xmlArr[0]["elements"] as $el) {
    $desc[$el["name"]]=$el["text"];
  }
  
  // plugin with the same name must not be activated. otherwise exit
  $ret = getPluginByName($desc['name']);
  if (count($ret)) {
   //error_log("plugin is with the same name is already activated");
   return 0;
  }

  
  
  //
  // get plugin data
  //
  $xmlArr=xml2array($pld);
  //errArr($xmlArr);
  
  // root node must be <plugindata> to be valid
  if ($xmlArr[0]['name'] != 'plugindata') {
    //error_log("missing valid plugindata. no valid plugin");
    return 0;
  }
  
  
  // ok - seems valid. lets walk though the vo-objects and add them to the system
  // however, we need to fix references, because all new objects will get new id's
  // i.e if a plugin imports an app and a macro, then we need to adjust the reference to the macro in the app.
  // for this we use an associative array that maps old and new id's.
    
  // map old and new id's. [type][$importId]=newId
  $idMapper = array();
  
  // need to loop 2 times. 
  // 1st to get the new id's for all elements if necessary
  // 2nd to fix the references via $idMapper and rebuild the objects
  // if all objects already existed, we break and omnit the 2nd loop. 
  $lStates = array('stInit', 'stFixId');
  foreach ($lStates as $lState) {  
    
    foreach ($xmlArr[0]['elements'] as $item) {
      
      unset($entry);
      $type = $item["name"];
      switch ($type) {
        
        // xml element is macro
        // we do not need to fix anything in stFixId
        case "macro":
          if ($lState == 'stFixId') {  break; }
                    
          foreach ($item["elements"] as $el) {
            $entry[$el["name"]] = $el["text"];
            
            // get the $importId for the idMappper
            if ($el["name"] == "id") { $importId = $el["text"]; }
            
            // get the parameter section
            if ($el["name"] == "parameter") {
              $txt = "";
              // Not every plugin or macro has paramter its optional
              if (is_array($el["elements"])) {
                foreach ($el["elements"] as $e) {
                  $txt .= "<param name=\"" . $e["attributes"]["name"] . "\" type=\"" . $e["attributes"]["type"];
                  $txt .= "\" label=\"" . $e["attributes"]["label"] . "\" description=\"" . $e["attributes"]["description"] . "\" />";
                }
              }
              $entry[$el["name"]] = $txt;
            } //if  parameter
            
          }
          // put macro by name, not by id. 
          $newId = putMacro($entry, false);
          if ($lState == 'stInit') { 
            $entity[$type][] = $newId; 
            //error_log("inserted macro id $newId");
            // add the ID to the mapping table if it is different
            if ($importId != $newId) { $idMapper[$type][$importId] = $newId; }
          }
        break;

        
        // xml element is application
        // we need to fix the id's of macro references in stFixId
        case "application": 
          foreach ($item["elements"] as $el) {
            // if tag groups then enter the group list
            if ($el["name"]=="groups") {
              foreach($el["elements"] as $group) $groups[$group["name"]]=$group["text"];
              $entry[$el["name"]] = $groups;
            }
            else $entry[$el["name"]] = $el["text"];
            
            // check the id
            if ($el["name"] == "id") { 
              // in stInit store the $importId for the idMapper
              if ($lState == 'stInit') { $importId = $el["text"]; } 
              // fixid: in stFixId use the newId assigned as in stInit
              if ($lState == 'stFixId') {
                if ($idMapper['application'][$el["text"]] != "") { $entry[$el["name"]] = $idMapper['application'][$el['text']]; }
              }
            }
  
            // fix reference to the macro
            if ($el["name"] == "macro") { 
              if  ($lState == 'stFixId') {
                if ($idMapper['macro'][$el["text"]] != "") { $entry[$el["name"]] = $idMapper['macro'][$el['text']]; } 
              }
            }
            
          } // foreach 
          // put application by name, not by id. request reload

          $newId = putApplication($entry, false);
          if ($lState == 'stInit') { 
           $entity[$type][] = $newId;
            //error_log("inserted application id $newId");
            // add the ID to the mapping table if it is different
            if ($importId != $newId) { $idMapper[$type][$importId] = $newId; }  
          }
        break;
        
        
        // xml element is queue 
        // so far we do not support extensions and therefore we do not need to fix anything in stFixId
        // even we would, how would we translate queuemember?       
        case "queue": 
          // if we suport extensions, we might have to change this!
          if ($lState == 'stFixId') {  break; }

          foreach ($item["elements"] as $el) {
            $entry[$el["name"]] = $el["text"];
            // get the $importId
            if ($el["name"] == "id") { $importId = $el["text"]; }
            if ($el["name"] == "member") { 
              foreach ($el["elements"] as $e) { $v[] = $e["text"]; }
              $entry['member'] = $v;
            }
          }
          // putQueue by name, not by id
          $newId = putQueue($entry, false);
          if ($lState == 'stInit') { 
            $entity[$type][] = $newId; 
            //error_log("inserted queue id $newId");
            // add the ID to the mapping table if it is different
            if ($importId != $newId) { $idMapper[$type][$importId] = $newId; }  
          }                   
        break;
        
        default:
          //error_log("item not supported");
        break;
        
      }
    } // foreach tag 
  
    // if all objects have existed, than no id's will have changed. so we do not need a 2nd run
    if ((count($idMapper) == 0) and ($lState == 'stInit')) { break; }
  
  } // foreach

    
  // 
  // update database with the new plugin information
  //
      
  
  // build information array. map database fields
  $d_name = $desc['name'];
  $d_label = $desc['label'];
  $d_package_name = $desc['packageName'];
  $d_version = $desc['version'];
  $d_date = $desc['date']; 
  $d_description = $desc['description'];
  $d_author_name = $desc['authorName'];
  $d_author_email = $desc['authorEmail'];
  $d_author_website = $desc['authorWebsite'];
  $d_vo_version = $desc['voVersion'];
  $d_vo_pl_version = $desc['voPlVersion'];

  $qry = "INSERT INTO cw_plugin ";
  $qry .= " (name, label, package_name, version, date, description, author_name, author_email, author_website, vo_version, vo_pl_version) ";
  $qry .= " VALUES ";
  $qry .= " ('".string2sql($d_name)."','".string2sql($d_label)."','".string2sql($d_package_name)."','".string2sql($d_version)."',";
  $qry .= "'$d_date','".string2sql($d_description)."','".string2sql($d_author_name)."','".string2sql($d_author_email)."',";
  $qry .= "'".string2sql($d_author_website)."','".string2sql($d_vo_version)."','".string2sql($d_vo_pl_version)."')";
   
  //error_log($qry);
  $res=$db->Execute($qry);
  // get new plugin id
  $plugin_id = $db->Insert_ID();
  
  // update cw_plugin_entity
  foreach ($entity as $etype=>$elist) {
    foreach ($elist as $elId) {   
   
    $d_plugin_id = $plugin_id;
    $d_entity_id = $elId;
    // we store the entity type verbose like "macro" or "application".
    // this is because we do not have unique id's for all entity types.
    // might change in future version
    $d_entity_type = $etype;
    // not supported so far because entities do not maintain a version
    $d_entity_version = "";
       
    $qry = "INSERT INTO cw_plugin_entity ";
    $qry .= " (plugin_id, entity_type, entity_id, entity_version) ";
    $qry .= " VALUES ";
    $qry .= " ($d_plugin_id,'".string2sql($d_entity_type)."',$d_entity_id,'".string2sql($d_entity_version)."') ";
     
    $res=$db->Execute($qry); 
    }
  }
  
  return 1;
}

// ---- delPlugin(id:int):int ---------------------------

/**
 * Delete a plugin from the system by $id. Removes all entities (vo-objects) that are part of the plugin in case they are not used by other plugins
 * 
 * @param integer $id of plugin to delete
 * @return integer 1
 * @see putPlugin
 * @see getPluginByName
 * @see getPluginByPackageName
 * @see getPluginByEntity
 * @see getPluginEntities
 * @todo handle errors, return errorcodes, pass info about vo-objects back  (removed/kept)
 */
 function delPlugin($id) {
  global $db;
  // remove vo-objects (entities) in case they are not used by other plugins
  $entities = getPluginEntities($id);
  foreach ($entities as $entity) {
    $type = $entity['entity_type'];
    $plList = getPluginbyEntity($entity['entity_type'], $entity['entity_id']);
    if (is_array($plList) and (count($plList) == 1)) {
      // entity is only used by one plugin, so we remove it
      switch ($type) {
        case "application":
          $ret = delApplication($entity['entity_id'], true);
        break;
        case "macro":
          $ret = delMacro($entity['entity_id'], true);
        break;
        case "queue":
          $ret = delQueue($entity['entity_id']);
        break;
      } // switch
    } // if
  } // foreach 
  
  
  // delete plugin describtion

  $qry="DELETE FROM cw_plugin WHERE id=$id";
  $ret = $db->Execute($qry);
  // delete plugin objects
  $qry="DELETE FROM cw_plugin_entity WHERE plugin_id=$id";
  $ret = $db->Execute($qry);
  
  
  return 1;
}

//******************************************************************************
//******************               extensions.conf             *****************
//******************************************************************************
  
  
// ---- writeExtensionsConf():int ---------------------------

function writeExtensionsConf($reload=true) {
  global $db,$misdnPrefix;

  //remove all rows of sip.conf. It will be regenerated
  $res=delAstConfig("extensions.conf","%");

  //insert the GENERAL OPTION  
  $arr=getConfOption("",OPTION_EXTENSION_GENERAL,0);
  if (is_array($arr))
  foreach ($arr as $v) {
    if ($v["value"]=="") $value=$v["default"]; else $value=$v["value"];
    if ($v["commented"]!="1") $res=putAstConfig("extensions.conf", "general", $v["name"], $value);
  }  
    
  //insert the GLOBALS OPTION  
  $arr=getConfOption("",OPTION_EXTENSION_GLOBALS,0);
  if (is_array($arr))
  foreach ($arr as $v) {
    if ($v["value"]=="") $value=$v["default"]; else $value=$v["value"];
    if ($v["commented"]!="1") $res=putAstConfig("extensions.conf", "globals", $v["name"], $value);
  }  

  //if asterisk is ON, reload sip
  if ($reload===true){
    $status=pbxSwitch("status");
    if($status=="ON") $ret=sendCommand("sip reload");
  }
    
  return $ret;
}
  
//******************************************************************************
//*******************           write .conf file             *******************
//******************************************************************************
  
// ---- writeConf(filename:string):int --------------------------------

function writeConf() {
  global $db,$voTools;

  // retrieve .conf file names
  $qry="SELECT DISTINCT `file` FROM `cw_config_file`";
  $res=$db->Execute($qry);  
  while($arr=$res->FetchRow()) $filenames[]=$arr["file"]; 
  // load .conf files
  foreach($filenames as $filename){
    //remove all rows of filename. It will be regenerated
    $res=delAstConfig($filename,"%");
    //specific actions to do before load .conf files
    switch ($filename) {
      case "musiconhold.conf":
        //update cw_option
        exec("sudo $voTools getMohDir",$output,$retScript);
        $dir=$output[0]."/voiceone/default";
        $qry="UPDATE `cw_option` SET `default` = '".string2sql($dir)."' WHERE `category`='MOH' AND `name`='directory' LIMIT 1;";
        $res=$db->Execute($qry);
        //section to write
        $section=1;
      break;
      case "features.conf":
      case "queues.conf":
      case "agents.conf":
        //section to write
        $section=1;
      break;
    } 
    //retrieve categories
    $qry="SELECT `tag` , `category` FROM `cw_config_file` WHERE `file`='".string2sql($filename)."'";
    $res=$db->Execute($qry);
    $i=0; 
    $ret=array();
    while ($arr=$res->FetchRow()) { 
      $ret[$i]["tag"]=$arr["tag"];
      $ret[$i]["name"]=$arr["category"];
      $i++;
    }
    //read cw_option and write ast_config  
    if(is_array($ret)){
      foreach($ret as $cat){
        $arr=getConfOption("",$cat["tag"],$section);
        if (is_array($arr)){
          foreach ($arr as $v){
            if ($v["value"]=="") $value=$v["default"]; else $value=$v["value"];
            //if ($v["commented"]==0) putAstConfig($filename, $cat["name"], $v["name"], $value, $v["comment"], $v["commented"]);
            putAstConfig($filename, $cat["name"], $v["name"], $value, $v["comment"], $v["commented"]);
          }
        }  
      }
    }
  }//while
  return 1;
}  

//******************************************************************************
//******************               INITIALIZE               ********************
//******************************************************************************

// ---- initialize():int ----------------------------------------------------

function initialize($genKeys) {
  error_log("  -> Add global");
  global $db,$synDbUser,$synDbPassword,$voiceoneWSDocumentRoot,$voiceoneWSDirName;
  global $keyName,$sandboxServer,$voTools,$synDbName,$synDbHost,$outgoing_prefix;
  
  //stop Asterisk
  error_log("  -> Stop asterisk");
  exec("sudo $voTools asterisk_stop",$out);
  errArr($out);
  
  //stop mISDN driver
  error_log("  -> Stop mISDN");
  exec("sudo $voTools misdn_init stop",$out);
  errArr($out);
  
  //remove all the tables 
  //TODO: remove only voiceone tables
  error_log("  -> Drop tables");
  $tables=$db->MetaTables('TABLES');
  if (is_array($tables))
  foreach ($tables as $t) $db->Execute("DROP TABLE `$t`");

  //write the right file permission
  $doc_root=substr($voiceoneWSDocumentRoot,0,-strlen($voiceoneWSDirName)-1);
  exec("sudo $voTools install ".$doc_root,$out);
  error_log("sudo $voTools install ".$doc_root );

  /************************       IMPORT DB       *****************************/
  error_log("Importing the database...");
  //insert core structures
  $imported=false;
  $db_core=$voiceoneWSDocumentRoot."/modules/core/db";
  if($handle=@opendir($db_core)){
    while(false!==($file=@readdir($handle))){
      if(($file!=".")&&($file!="..")&&($file=="dump.sql")){
        $filePath=$db_core."/".$file;
        exec("cat $filePath | mysql --user=$synDbUser --password=$synDbPassword --host=$synDbHost $synDbName",$out);
        $imported=true;
      }
    }
    closedir($handle);
  }
  if($imported===true){
  	error_log("  -> core:".str_repeat(" ",30-strlen("core"))."   IMPORTED  ");
  }else{
  	error_log("  -> core:".str_repeat(" ",30-strlen("core"))." NOT IMPORTED");
  }
  //insert module structure (all about the core)
  $modules_dir=$voiceoneWSDocumentRoot."/modules";
  if($handle=@opendir($modules_dir)) {
    while(false!==($module=@readdir($handle))){
      if(($module!=".")&&($module!="..")&&(substr($module,0,1)!=".")&&(strtolower(trim($module))!="core")&&(@is_dir($modules_dir."/".$module))){
      	$imported=false;
        $db_module=$modules_dir."/".$module."/db";
        if($mod_handle=@opendir($db_module)){
          while(false!==($file=@readdir($mod_handle))){
            if(($file!=".")&&($file!="..")&&($file=="dump.sql")){
              $filePath=$db_module."/".$file;
              exec("cat $filePath | mysql --user=$synDbUser --password=$synDbPassword --host=$synDbHost $synDbName",$out);
              $imported=true;
            }
          }
          closedir($mod_handle);
        }
        if($imported===true){
        	error_log("  -> ".$module.":".str_repeat(" ",30-strlen($module))."   IMPORTED  ");
        }else{
        	error_log("  -> ".$module.":".str_repeat(" ",30-strlen($module))." NOT IMPORTED");
        }
      }
    }
    closedir($handle);
  }
  //write the mISDN configuration 
  writeExtensionsConf(false);
  
  //write .conf files
  writeConf();
  
  //initialize3 cw_sounds_file
  $ret=soundsInit();
  
  //create the metagroups
  putGroup(Array("id"=>GROUP_OF_ALL,          "name"=>"_all_",              "type"=>GROUP_OF_ALL,         "metagroup"=>1));
  putGroup(Array("id"=>GROUP_OF_EXTENSION,    "name"=>"_all-extensions_",   "type"=>GROUP_OF_EXTENSION,   "metagroup"=>1));
  putGroup(Array("id"=>GROUP_OF_RESOURCE,     "name"=>"_all-resources_",    "type"=>GROUP_OF_RESOURCE,    "metagroup"=>1));
  putGroup(Array("id"=>GROUP_OF_OFFICE,       "name"=>"_all-offices_",      "type"=>GROUP_OF_OFFICE,      "metagroup"=>1));
  putGroup(Array("id"=>GROUP_OF_APPLICATION,  "name"=>"_all-applications_", "type"=>GROUP_OF_APPLICATION, "metagroup"=>1));
  putGroup(Array("id"=>GROUP_OF_PHONENUMBER,  "name"=>"_all-phonenumbers_", "type"=>GROUP_OF_PHONENUMBER, "metagroup"=>1));
  
  //create the MetaGroup inclusions
  $res=putAstConfig("extensions.conf","_all_","include","_all-extensions_");
  $res=putAstConfig("extensions.conf","_all-extensions_","","","All Extensions",1);
  //$res=putAstConfig("extensions.conf","_all_","include","_all-offices_");
  $res=putAstConfig("extensions.conf","_all_","include","_all-resources_");
  $res=putAstConfig("extensions.conf","_all-resources_","","","All Resources",1);
  $res=putAstConfig("extensions.conf","_all_","include","_all-applications_");
  $res=putAstConfig("extensions.conf","_all-applications_","","","All Applications",1);
  //$res=putAstConfig("extensions.conf","_all_","include","_all-phonenumbers_"); WARNING: phone numbers are out of dialplan!!!
  $res=putAstConfig("extensions.conf","_all_","include","_catch-all_");
  $res=putAstConfig("extensions.conf","_catch-all_","","","Catch All",1);
  if ($outgoing_prefix=="") {
    //$res=putAstConfig("extensions.conf","_catch-all_","exten","_X.,1,NoOp(Catch-All triggered. CallerID:\${CALLERID(all)} - Calling:\${EXTEN})");
    $res=putAstConfig("extensions.conf","_catch-all_","exten","_X.,1,AGI(dial.php,entity=&group=".GROUP_OF_PHONENUMBER."&extension=\${EXTEN})");
    //$res=putAstConfig("extensions.conf","_catch-all_","exten","_X,1,NoOp(Catch-All triggered. CallerID:\${CALLERID(all)} - Calling:\${EXTEN})");
    $res=putAstConfig("extensions.conf","_catch-all_","exten","_X,1,AGI(dial.php,entity=&group=".GROUP_OF_PHONENUMBER."&extension=\${EXTEN})");
  }  else { 
    $res=putAstConfig("extensions.conf","_catch-all_","exten","_".$outgoing_prefix.".,1,AGI(dial.php,entity=&group=".GROUP_OF_PHONENUMBER."&extension=\${EXTEN})");
  }
	
  //create defualt context (for incoming call sended by not registered clients)
  $res=putAstConfig("extensions.conf","default","exten","_[a-zA-Z0-9].,1,Hangup");
  $res=putAstConfig("extensions.conf","default","exten","_[a-gj-ru-zA-Z0-9],1,Hangup");
  $res=putAstConfig("extensions.conf","default","exten","s,1,Hangup");
  $res=putAstConfig("extensions.conf","default","exten","t,1,Hangup");
  $res=putAstConfig("extensions.conf","default","exten","i,1,Hangup");

  // Load System Plugin
  $pli = file_get_contents($voiceoneWSDocumentRoot."/config/backup/plugininfo.xml"); 
  $pld = file_get_contents($voiceoneWSDocumentRoot."/config/backup/plugindata.xml"); 
  $ret = putPlugin($pli, $pld);

  //Create the first Outgoing Rule
  $arr=Array("name"=>"DefaultOutgoingRule","type"=>RULE_OUTGOING);
  $rule=putRule($arr);
  $arr=Array ("rule"=>$rule,"timesegment"=>0,"action"=>1,"resource"=>0,"group"=>GROUP_OF_ALL);
  $ret=putOutgoingRule($arr);
  
  //Create the first Incoming Rule
  $arr=Array("name"=>"DefaultIncomingRule","type"=>RULE_INCOMING);
  $rule=putRule($arr);
  $inc_macro=getMacroByName("incoming-call-to-group");
  $arr=Array ("rule"=>$rule,"timesegment"=>0,"callertype"=>CALLER_ALL,"macro"=>$inc_macro[0]['id'],"parameter"=>"dest=".GROUP_OF_EXTENSION);
  $ret=putIncomingRule($arr);

  ////write the mISDN configuration 
  //writeMIsdn(false);  
  ////write the SIP configuration 
  //writeSIP(false);  
  ////write the SIP configuration 
  //writeIAX(false);
  
  //write conf settings
  $techArr=getTechnology(null);
  foreach ($techArr as $t) {
    //$ret=putOption($t["id"],null,false);
    $ret=putOptionInAstConfig($t["id"],null,false);
  }    
 
  //generate the global variable
  generateGlobalVar();

  //Generate the private and public key and move it in the right position
  if ($genKeys==1) {
    exec("sudo $voTools astgenkey $voiceoneWSDocumentRoot/sandbox/ $keyName ",$output,$retScript);
    exec("sudo $voTools inkey \"$voiceoneWSDocumentRoot/sandbox/$keyName\" ",$output,$retScript);
  }
  
  //error_log("Setup Completed");
  //the asterisk is now DOWN. It will be started when the first isdn card is 
  //installed.

  return $ret;
}

  
  

//******************************************************************************
//******************               DIRECTORY               ********************
//******************************************************************************

// ---- getDirectory():directory[] -----------------------------------

function getDirectory() {
  global $db;

  
  $start=false;
  $peers=sendCommand("sip show peers");
  if ($peers!="") {
    $lines=split("\n",$peers);
    foreach ($lines as $l) {
      if (strpos($l,"online")!==false) $start=false;
      if ($start) {
        $infos=split("[ ]+",$l);
        $userArr=split("/",$infos[0]);
        $username=$userArr[1];
        if (strpos($l,"UNKNOWN")!==false) $peerInfo[$username]="UNKNOWN";
        if (strpos($l,"Unmonitored")!==false) $peerInfo[$username]="Unmonitored";
        if (strpos($l,"OK")!==false) $peerInfo[$username]="OK";
      }
      if (strpos($l,"Name")!==false) $start=true;
    }
  } 

  $start=false;
  $peers=sendCommand("iax2 show peers");
  if ($peers!="") {
    $lines=split("\n",$peers);
    foreach ($lines as $l) {
      if (strpos($l,"online")!==false) $start=false;
      if ($start) {
        $infos=split("[ ]+",$l);
        $userArr=split("/",$infos[0]);
        $username=$userArr[1];
        if (strpos($l,"UNKNOWN")!==false) $peerInfo[$username]="UNKNOWN";
        if (strpos($l,"Unmonitored")!==false) $peerInfo[$username]="Unmonitored";
        if (strpos($l,"OK")!==false) $peerInfo[$username]="OK";
      }
      if (strpos($l,"Name")!==false) $start=true;
    }
  }

  
  $ext=getClient(0);
  if (is_array($ext))
  foreach($ext as $v) {
    $name=$v["name"]." ".$v["surname"]." <".$v["extension"].">";
    $username=$v["extension"];
    if (isset($peerInfo[$username])) $status=$peerInfo[$username];
    else $status="UNKNOWN";
    $arr=array("name"=>"$name", "username"=>"$username", "status"=>"$status");
    $ret[]=$arr;
  }
  return $ret;
}


//******************************************************************************
//******************               USER                     ********************
//******************************************************************************

// ---- getUser(id:int):user[] -----------------------------------
function getUser($id) {
  global $db,$synDbName;
  //check if table exists (need in setup.php)
  $tablesArr=array();
  $qry="SHOW TABLES";
  $res=$db->Execute($qry);
  while($arr=$res->FetchRow()) $tablesArr[]=trim($arr["Tables_in_".$synDbName]);
  if(!is_array($tablesArr)) return array();
  else if(!in_array("cw_user",$tablesArr,true)) return array();
  //get users
  if ($id!="") $condition=" WHERE id=$id ";
  $qry="SELECT * FROM cw_user $condition";
  $res=$db->Execute($qry);
  while($arr=$res->FetchRow()){
    $id=$arr["id"];
    $type=$arr["type"];
    $lang=$arr["lang"];
    $entity_id=$arr["entity_id"];
    if($entity_id!=0){
    	//user is an extension
      $client=getClient($entity_id);
      if((is_array($client))&&(is_array($client[0]))){
        $c=$client[0];
        $fullname=$c["name"]." ".$c["surname"];
        $username=$c["extension"];
        $password=$c["password"];
        $exten=$c["extension"];
        $technology=$c["technology"];
        $entity_id=$entity_id;
      }
      //user is a virtual extension
      else{
      	$virtual=getVirtualExtension($entity_id);
        if((is_array($virtual))&&(is_array($virtual[0]))){
          $v=$virtual[0];
          $fullname=$v["name"]." ".$v["surname"];
          $username=$arr["username"];
          $password=$arr["password"];
          $exten=$v["extension"];
          $entity_id=$entity_id;
        }
      }
    }
    //user doesn't have extension
    else{
      $username=$arr["username"];
      $password=$arr["password"];
      $entity_id=0;
    }
    $ret[]=array("id"=>$id, "fullname"=>$fullname, "username"=>$username, "password"=>$password, "lang"=>$lang, "entity_id"=>$entity_id, "exten"=>$exten, "technology"=>$technology, "type"=>$type);
  }
  return $ret;
}

// ---- putUser(user:User):int -----------------------------------
function putUser($user) {
  global $db;
  $id="";
  $id_value="";
  
  //if already exists, delete it
  if (isset($user["id"]) and $user["id"]!="") {
    delUser($user["id"],false);
    $id="id,";
    $id_value=$user["id"].",";
  }
  
  if($user["type"]=="") $user["type"]=USER_STANDARD;
	if($user["lang"]=="") $user["lang"]="en";
  
  //insert the client credentials
  $qry="INSERT INTO cw_user ($id username,password,lang,type,entity_id) ";
  $qry.="VALUES ($id_value '".string2sql($user['username'])."','".string2sql($user['password'])."',";
  $qry.="'".string2sql($user['lang'])."','".$user['type']."','".$user['entity_id']."')";
  $res=$db->Execute($qry);
  if ($res===false) $ret=0; 
  elseif ($user["id"]=="") $ret=$db->Insert_ID();
  else $ret=$user["id"];

  return $ret;
}

// ---- delUser(id:int):int --------------------------------------------------

function delUser($id) {
  global $db;

  //remove the user
  $qry="DELETE FROM cw_user WHERE id=".$id;
  $db->Execute($qry);
  
  return 1;
}

// ---- checkUser(username:string, password:string):int --------------------------------------------------
// PS: password must be an md5 password

function checkUser($username, $password) {
  global $db;
  //error_log("sono in chk user");
  $ret=0;
  $u=getUser(0);
  if (is_array($u))
  foreach($u as $user) {
    if ($user["username"]==$username AND md5($user["password"])==$password) $ret=$user["id"];
  }
  return $ret;
}

// ---- viewAstConfigFilename():string[] ---------------------------------------

function viewAstConfigFilename() {
  global $db;
  $qry="SELECT DISTINCT filename FROM ast_config";
  $res=$db->Execute($qry);
  while ($arr=$res->FetchRow()) $ret[]=$arr["filename"];
  return $ret;
}

// ---- viewAstConfig(filename:string):string ---------------------------------------

function viewAstConfig($f) {
  global $db;
  //extract file
  $qry="SELECT DISTINCT filename FROM ast_config WHERE filename='".string2sql($f)."'";
  $res=$db->Execute($qry);
  while($arr=$res->FetchRow()) {
    $filename=$arr["filename"];
		//extract categories
    $qry="SELECT DISTINCT category,zsection FROM ast_config WHERE filename='".string2sql($filename)."' ORDER BY cat_metric,zsection";
    $res2=$db->Execute($qry);
    while($arr=$res2->FetchRow()) {
      $category=$arr["category"];
      $zsection=$arr["zsection"];
      $ret.= "\n";
      if($zsection!=""){
        $ret.= ";[".$zsection."]\n"; //added for Zapata
      }else{
        $ret.= "[".$category."]\n";
      }
      //extract parameters
      $qry="SELECT * ";
      $qry.="FROM ast_config ";
      $qry.="WHERE filename='".string2sql($filename)."' ";
      $qry.="AND category='".string2sql($category)."' ";
      $qry.="AND zsection='".$zsection."' ";
      $qry.="ORDER BY var_metric";
      $res3=$db->Execute($qry);
      while ($arr=$res3->FetchRow()) {
        $var_name=$arr["var_name"];
        $var_val=$arr["var_val"];
        $comment=$arr["comment"];
        $commented=$arr["commented"];
        if($var_name!="" and $commented!=1){
        	if(($zsection!="")&&($var_name=="channel")){
          	$ret.="$var_name => $var_val"; //added for Zapata
          }else{
        		$ret.="$var_name = $var_val";
          }
        }
        if($var_name!="" and $commented==1){
        	if(($zsection!="")&&($var_name=="channel")){
            $ret.="; $var_name => $var_val"; //added for Zapata
          }else{
            $ret.="; $var_name = $var_val";
          }
        }
        if($comment!="" and $var_name!="") $ret.= "\t ;$comment";
        if($comment!="" and $var_name=="") $ret.= ";$comment";
        $ret.="\n";
      }
    }
  }
  return $ret;
}

// ---- createAstConfig(lines:stringArray, filename:string):int ----------------
function createAstConfig($lines,$filename) {
  global $db;
  // remove all the old records about the file
  $qry="DELETE FROM ast_config WHERE filename='".string2sql($filename)."'";
  $res=$db->Execute($qry);
  // loop lines and insert text
  $cat_metric=-1;
  $var_metric=0;
  $zsection="";
  if(is_array($lines)){
    foreach($lines as $line_num => $line) {
      $line=trim($line);
      //empty line: skip
      if($line[0]=="") continue;
      //zsection: extract and save variable
      else if(($line[0]==";")&&($line[1]=="[")){
        $zsection=substr($line,2,strpos("]",$line)-1);
        continue;
      }
      //commented line: save as comment
      else if($line[0]==";"){
        $comment=str_replace("\"","'",trim(substr(trim($line),1)));
        $var_name="";
        $var_val="";
        $commented=1;
        $var_metric++;
      }
      //valid line: process it...
      else{
        $commented="0";
        //category
        if($line[0]=="["){
          $arr_comm=split(";",trim($line));
          $category=substr(trim($arr_comm[0]),1,strlen(trim($arr_comm[0]))-2);
          $comment=trim($arr_comm[1]);
          $cat_metric++;
          $var_metric=-1;
          continue;
        }
        //parameter
        else{
          $arr=split("=|=>",$line);
          $var_name=trim($arr[0]);
          unset($arr[0]);
          $arr_comm=split(";",trim(implode("=", $arr)));
          if(!is_array($arr_comm)) continue;
          else{
            $var_val=$arr_comm[0];
            $comment="";
            $alreadyCommented=false;
            for($i=0;$i<(count($arr_comm)-1);$i++){
              $sub_before=$arr_comm[$i];
              $sub_after=$arr_comm[($i+1)];
              if((strlen($sub_before)>0)&&($sub_before[(strlen($sub_before)-1)]=="\\")&&($alreadyCommented===false)){
                $var_val.=";".$sub_after;
              }else{
                if($comment=="") $comment.=$sub_after; else $comment.=";".$sub_after;
                $alreadyCommented=true;
              }
            }
          } 
          $var_val=trim($var_val);
          $comment=trim($comment);
          $var_metric++;
        }  
      }
      $qry="INSERT INTO ast_config (cat_metric,var_metric,commented,filename,category,var_name,var_val,comment,zsection)";
      $qry.="VALUES ($cat_metric,$var_metric,$commented,'".string2sql($filename)."','".string2sql($category)."',";
      $qry.="'".string2sql($var_name)."','".string2sql($var_val)."','".string2sql($comment)."','".string2sql($zsection)."')";
      $res=$db->Execute($qry);
      if($res==false) return 0;    
    }
  }
  //return
  return 1;
}
// ---- getPublicKey():string ----------------
function getPublicKey() {
  global $db,$keyName, $voiceoneWSDocumentRoot;
  //$filename="/var/lib/asterisk/key/".$keyName.".pub";
  $filename=$voiceoneWSDocumentRoot."/sandbox/".$keyName.".pub";
  if (file_exists($filename)) {
    $hi = fopen($filename,"r");
    $ret = fread($hi,filesize($filename));
    fclose($hi);
  } else $ret="[none]";  
  //$ret=file_get_contents ("/var/lib/asterisk/key/".$keyName".pub");
  return $ret;
}

// ---- stats(source:String, type:String, search:String, from:String, to:String, orderBy:String, page:Int ):CdrArray ----------------
/**
* Get CDR (Call Detail Record) Information
* @param array (source:String, type:String, search:String, from:String, to:String, orderBy:String, page:Int)
* @return CdrArray
* @todo add more information like Callstate (Answer, Failed, No Answer, wether this is incoming or outgoing), make entries per page dynamic via frontend request
* @todo add validation to date etc. so frontend cannot make query fail., add error codes
*/
function stats($request) {
  global $db;
  $ENTRIES_PER_PAGE=20;

  $source = trim($request["source"]);
  $type=$request["type"];
  $search=$request["search"];
  $from=$request["from"];
  $to=$request["to"];
  $orderBy=$request["orderBy"];
  $page=$request["page"];

  //where statement
  if ($source!="") {
    if (($type=="a" or $type=="r") ) $where.="OR  SUBSTRING(dstchannel FROM 1 FOR INSTR(dstchannel,'-')-1 )='$source' ";
    if (($type=="a" or $type=="r") and $search!="") $where.="AND src='$search' ";
    if (($type=="a" or $type=="d") ) $where.="OR  SUBSTRING(channel FROM 1 FOR INSTR(channel,'-')-1 )='$source' ";
    if (($type=="a" or $type=="d") and $search!="") $where.="AND dst='$search' ";
  } else {
    if ($search!="") $where.="AND (src='$search' or dst='$search') ";
  }
  if ($from!="") $where.="AND calldate>='$from' ";
  if ($to!="") $where.="AND calldate<='$to' ";

  //order by statment
  if ($orderBy=="dateDesc") $orderBy="ORDER BY calldate DESC";
  else if ($orderBy=="dateAsc") $orderBy="ORDER BY calldate";
  else if ($orderBy=="durationDesc") $orderBy="ORDER BY duration DESC";
  else if ($orderBy=="durationAsc") $orderBy="ORDER BY duration";

  //pagination
  if ($page=="") $page=1;
  $entries=$ENTRIES_PER_PAGE*(intval($page)-1);
  $limit=" LIMIT $entries,$ENTRIES_PER_PAGE";

  //Query Execution
  $where=trim(substr($where,3));
  if ($where!="") $where="WHERE ".$where;
  $qry="SELECT * FROM cdr $where $orderBy $limit";
  $res=$db->Execute($qry);
  while ($arr=$res->FetchRow()) {
    $answer=substr($arr["dstchannel"],0,strrpos($arr["dstchannel"],"-"));
    $caller=substr($arr["channel"],0,strrpos($arr["channel"],"-"));
    if ($answer==$source) {
      if ($arr["clid"]=="") $arr["clid"]="Anonymous";
      $ret["received"]=$arr["clid"];
      $ret["dialed"]="";
      $ret["channel"]=$arr["channel"];
    }
    if ($caller==$source) {
      $ret["received"]="";
      $ret["dialed"]=$arr["dst"];
      $ret["channel"]=$arr["src"];
    }
    if ($source=="") {  //show all the calls
      if ($arr["clid"]=="") $arr["clid"]="Anonymous";
      $ret["received"]=$arr["clid"];
      $ret["dialed"]=$arr["dst"];
    }
    $ret["entity"]=$source;
    $ret["calldate"]=$arr["calldate"];
    $ret["duration"]=$arr["duration"];

    $result[]=$ret;
  }

  //error_log($qry);

  return $result;
}






//******************************************************************************
//******************               TIME SEGMENT             ********************
//******************************************************************************

// ---- getTimeSegment(id:int ):TimeSegmentArray -------------------------------
function getTimeSegment($id) {
  global $db;
  if ($id!="") $condition=" WHERE id=$id ";
  $qry="SELECT * FROM cw_time_segment $condition";
  $res=$db->Execute($qry);
  while ($arr=$res->FetchRow()) {
    foreach($arr as $field=>$value) $v[$field]=$value;
    $ret[]=$v;
  }
  return $ret;
}

// ---- putTimeSegment(ts:TimeSegment ):int ------------------------------------
function putTimeSegment($ts) {
  global $db;
  // if modify, delete old timesegment
  if (isset($ts["id"]) and $ts["id"]!="") {
    delTimeSegment($ts["id"],false);
  }
  //insert new timesegment
  $qry="INSERT INTO cw_time_segment (id,name,date_from,date_to,hour_from,hour_to,week_day,day,month) "; 
  $qry.="VALUES ('".$ts["id"]."','".string2sql($ts["name"])."','".string2sql($ts["date_from"])."','".string2sql($ts["date_to"])."',";
  $qry.="'".string2sql($ts["hour_from"])."','".string2sql($ts["hour_to"])."','".string2sql($ts["week_day"])."','".string2sql($ts["day"])."','".string2sql($ts["month"])."') ";
  $res=$db->Execute($qry);
  //return
  if($res===false) return 0; else return 1;
  
  /* OLD IMPLEMENTATION */
  /*
  if (is_array($ts))
  foreach($ts as $k=>$v) {
    if ($v!="|" and $v!="") {
      $fieldName.="`".$k."`,";
      $fieldValue.="'".string2sql($v)."',";
    }
  }
  $fieldName=substr($fieldName,0,-1);
  $fieldValue=substr($fieldValue,0,-1);
  $qry="INSERT INTO cw_time_segment ($fieldName) VALUES ($fieldValue)";
  $res=$db->Execute($qry);
  //error_log($qry);
  if ($ts["id"]=="") $ret=$db->Insert_Id();
  else $ret=$ts["id"];
  return $ret;
  */
}

// ---- delTimeSegment(id:int ):int --------------------------------------------
function delTimeSegment($id) {
  global $db;

  $qry="DELETE FROM cw_time_segment WHERE id=$id";
  $res=$db->Execute($qry);
  //error_log($qry);
  return 1;
}

  
//******************************************************************************
//******************               MACRO                   ********************
//******************************************************************************

// ---- getMacro(id:int):Macro[] -----------------------------------
/**
 * Get macro by id or get all macros if id is not defined
 *
 * @param integer macroID. If none specified, then all macros are returned
 * @return array macro[] using the database record structure
 * @see putMacro
 * @see getMacroByName
 * @see resolveMacroParam
 */

function getMacro($id) {
  global $db;

  //get the technology name and compute the Channel name
  if ($id!="") $condition=" WHERE id=$id ";
  $qry="SELECT * FROM cw_macro ".$condition." ORDER BY label";
  $res=$db->Execute($qry);
  while ($arr=$res->FetchRow()) {
    foreach($arr as $field=>$value) $v[$field]=$value;
    $ret[]=$v;
  }
  return $ret;
}

/**
 * Get macro by name
 *
 * @param string $name. 
 * @return array macro[] using the database record structure
 * @see putMacro
 * @see getMacro
 * @see delMacro
 * @see resolveMacroParam
 */
function getMacroByName($name) {
  global $db;

  //get macro by name  
  $qry="SELECT * FROM cw_macro WHERE name='".string2sql($name)."' ORDER BY label";
  $res=$db->Execute($qry);
  while ($arr=$res->FetchRow()) {
    foreach($arr as $field=>$value) $v[$field]=$value;
    $ret[]=$v;
  }
  return $ret;
}


// ---- putMacro(macro:Macro, keepID:Boolean):int -----------------------------------

/**
 * Add a macro to the system 
 *
 * If the parameter array contains a value for ['id'] than putMacro tries to update the macro and keeps the id
 * @param array $macro macro:Macro
 * @param boolean $keepId default: true=keep Id regardless of the name; false=keep Id only if name matches
 * @return integer $entityId or 0 if failure 
 * @see getMacro
 * @see getMacroByName
 * @see delMacro 
 * @see resolveMacroParam
 */
function putMacro($macro, $keepId=true) {
  global $db,$realm;
  $entity=array();
  $ret=1;
  
  // Request for Update? 
  // By name or by id?  
  // Update via edit would be by id
  // Update via plugin would be by name
  // Otherwise we would risk to override a complete different entity via a plugin
  // So $keepId should be false if called via putPlugin.

  if ((isset($macro["id"])) and ($macro["id"] != "") and ($keepId == true)) {
    // id is set for new macro and must be used       
      $entity["id"] = $macro["id"];
      delMacro($entity["id"], false);
  } elseif ((isset($macro["name"])) and ($macro["name"] != "") and ($keepId == false)) {
    // name is set for new macro and must be used
    $curMacro = getMacroByName($macro["name"]);
    if ($curMacro[0]['name'] == $macro['name']) {
      // name matches, so update is ok      
      $entity["id"] = $curMacro[0]['id'];
      delMacro($entity["id"], false);
    }
  }
  
  //create a new entity
  $entity["type"]=MACRO;
  $entity_id=putEntity($entity);
  if (is_object($entity_id) or $entity_id==0) return 0;
  
  //insert the client credentials
  $name=$macro["name"];
  $label=$macro["label"];
  $description=$macro["description"];
  $parameter=$macro["parameter"];
  $code=$macro["code"];
  $qry="INSERT INTO cw_macro (id,name,label,description,code,parameter) ";
  $qry.="VALUES ($entity_id,'".string2sql($name)."','".string2sql($label)."',";
  $qry.="'".string2sql($description)."','".string2sql($code)."','".string2sql($parameter)."')";
  $res=$db->Execute($qry);
  if ($res===false) $ret=$ret and 0; else $ret=$ret and 1;
  
  //update the dialplan
  $before=true; $found=false; $after=false;
  $astconfig=viewAstConfig("extensions.conf");
  $arr=split("\n",$astconfig);
  foreach($arr as $line) {
    if (trim($line)=="[macro-$name]") {$found=true; $before=false;}
    if ($before===true) $astconfig_before[]=$line;
    if (substr(trim($line),0,1)=="[" and trim($line)!="[macro-$name]" and $found===true) {$found=false; $after=true;}
    if ($after===true)  $astconfig_after[]=$line;
  }  
  $arrCode=array_merge(Array("[macro-$name]"),split("\n",$macro["code"]));

  //$astconfig=array_merge($astconfig_before, $arrCode, $astconfig_after);
  
  // Assuming everything worked actually until here, $arrCode must be an array

  if (is_array($astconfig_before) && is_array($astconfig_after)) {
    $astconfig=array_merge($astconfig_before, $arrCode, $astconfig_after);
  } else {
    if (is_array($astconfig_before)) {
      $astconfig=array_merge($astconfig_before, $arrCode);
    } else { 
      $astconfig=array_merge($arrCode, $astconfig_after);
    }
  }
  // If $astconfig is empty, it will delete ast_config section extensions.conf
  // Perhaps this should really tested in createAstConfig before deleting 
  // everything accidentally !
  createAstConfig($astconfig,"extensions.conf");  
  
  //return value
  if ($ret==1) $ret=$entity_id; else $ret=0;

  //if asterisk is ON, reload extensions
  $status=pbxSwitch("status");
  if($status=="ON") sendCommand("reload");

  return $ret;
}

// ---- delMacro(id:int):int --------------------------------------------------
/**
 * Delete macro by id
 *
 * @param integer macroID. 
 * @param boolean $reload=true should asterisk perform a reload?
 * @return integer 1
 * @see putMacro
 * @see getMacro
 * @see getMacroByName
 * @see resolveMacroParam
 */

function delMacro($id,$reload=true) {
  global $db;

  //get the macro name
  $qry="SELECT * FROM cw_macro WHERE id=$id";
  $res=$db->Execute($qry);
  $arr=$res->FetchRow();
  $name=$arr["name"];

  //remove the macro from the macro table
  $qry="DELETE FROM cw_macro WHERE id=".$id;
  $db->Execute($qry);

  //delete macro from ast-config
  $qry="DELETE FROM ast_config WHERE filename='extensions.conf' AND category='macro-".string2sql($name)."'";
  $db->Execute($qry);
  
  //remove the entity from the asterisk tables
  $ret=delEntity($id);
  
  //if asterisk is ON, reload extensions
  if ($reload===true){
    $status=pbxSwitch("status");
    if($status=="ON") sendCommand("reload");
  }
  
  return 1;
}
// 
// ---- delMacro(id:int):int --------------------------------------------------
/**
 * Resolve macro parameter
 *
 * @param integer macroID
 * @param boolean string parameter list 
 * @return string resolved parameter list
 * @see putMacro
 * @see getMacro
 * @see getMacroByName
 * @see delMacro
 */
function resolveMacroParam($macroId,$parameters){
  $ret = prepareMacro($macroId,$parameters);
  return $ret[1];
}
  
//******************************************************************************
//******************               Version Check            ********************
//******************************************************************************

function versionCheck() {
  global $cw_version;
  
  $soapWsdl="";
  $soapWsdl = "http://root:voiceone@www.voiceone.it/admin/public/v1/?wsdl";
  $soapClient = new nusoapclient($soapWsdl, true);
  ini_set("soap.wsdl_cache_enabled", "1"); 
  $err = $soapClient->getError();
  if ($err) die('An error occurred while the WSDL was being accessed: '.$err);
  $v1server=$soapClient->getProxy();
  $v1server->setCredentials("root","voiceone");
  $v1server->useHTTPPersistentConnection();

  
  //pass the current VoiceOne version
  $entry=array( 
    array("key"=>"version", "value"=>$cw_version) 
  );
  
  //call the remote method
  $ret=$v1server->getLastVersion($entry);


  $ret[]=array("key"=>"current_version", "value"=>$cw_version);
  return $ret;
}

//******************************************************************************
//******************               I/O FUNCTION             ********************
//******************************************************************************


/**
* Reboot or shutdown the system
*
* @param string $action
* @return integer 1 = ok, 0 = error 
*/
function shutdown($action) {
  global $voTools;
  if ($action=="reboot") $param="-r now";
  else if ($action=="halt") $param="-h now";
  else return 0;
  system("sudo $voTools shutdown $param");
  error_log("sudo $voTools shutdown $param");
  // FIXME: log info
  return 1;
}

/**
* Start or Stop the PBX, or check its status
*
* @param string $action
* @return string ON = on, OFF = off, ERROR = error 
*/
function pbxSwitch($action){
  global $voTools;
  if ($action=="start"){
    error_log("ASTERISK START");
    exec("sudo $voTools asterisk_start",$output,$retScript);
    return $output[0];
  }
  else if ($action=="stop"){
    error_log("ASTERISK STOP");
    exec("sudo $voTools asterisk_stop",$output,$retScript);
    return $output[0];
  }
  else if ($action=="status"){
    exec("sudo $voTools asterisk_status",$output,$retScript);
    return $output[0];
  }
  return "ERROR";
}

//******************************************************************************
//******************               PRIVATE                  ********************
//******************************************************************************

/**
* Check wether an audiofile is used in any IVR
* Support Function. Scans IVR database for references to the audiofile
*
* @param string $filename
* @return integer 1 = used; 0 = not in use
*/
function isUsedIVRAudioFile($filename) {
  global $db;
  $qry="SELECT * FROM cw_ivr_node";
  $res=$db->Execute($qry);
  if ($res->RecordCount()>0) {
    while ($arr=$res->FetchRow()) {
      // IVR stores filenames in: audio, iaudio, taudio
      if (($arr["audio"] == $filename) or ($arr["iaudio"] == $filename) or ($arr["taudio"] == $filename)) {
	    // file is in use. exit.
		return 1;
      }
    }
  } 
  
  // file is not in use.
  return 0;
}

/**
* Sync audiofiles in IVR directory with the database.
* Allows to copy files into the filesystem and get them into the database for later use.
*
* @return integer 1 = new files added to database; 0 = Error: Files are referenced in database, but do not exist in filesystem
*/
// FIXME: needs implementation and testing
function syncIVRAudioFilesWithDB() {
  global $db, $ivrStartingDir;
  $qry="SELECT * FROM cw_audio";
  $res=$db->Execute($qry);
  if ($res->RecordCount()>0) {
    while ($arr=$res->FetchRow()) {
	  return 1;
    }  
  } else {
    return 1;
  }
}

//extract the base number from a list of numbers
function extractBaseNumber($numberString) {
  $numberArr=split("\|",$numberString);
  //errArr($numberArr);
  if (count($numberArr)>0) {
    $number=$numberArr[0];
    $numberLength=strlen($number);
    $ok=true;
    for ($l=0; $l<$numberLength; $l++){
      for ($i = 0; $i < count($numberArr); $i++) {
        if (substr($number,$l,1)==substr($numberArr[$i],$l,1)) $ok=$ok and true;
        else $ok=false;
      }
      if ($ok===true) $baseNumber.=$number[$l];
    }
  } 
  if (count($numberArr)==0 or $baseNumber=="") $baseNumber="X";
  return $baseNumber;
}





function test() {
 $ret=sendCommand("reload");
 print_r($ret);
 return;
}

// ---- generateGlobalVar(groups:int[]): int 
//create the global var in the Ast_Config

function generateGlobalVar($groups="") {
  global $db, $outgoing_prefix;

  //CREATE THE Channel VARIABLE
  $str="";
  $ret=getTrunk(0,0);
  if (is_array($ret)) 
  foreach($ret as $v) {
    $id=$v["id"];
    $str.=$v["name"]."&";
  }
  $app="TRUNK";
  $appdata=substr($str,0,-1); 
  $resAstConfig=delAstConfig("extensions.conf","globals",$app);
  $resAstConfig=putAstConfig("extensions.conf","globals",$app,$appdata);

  //OUTGOING PREFIX
  $app="OUTGOING_PREFIX";
  $appdata=$outgoing_prefix;
  $resAstConfig=delAstConfig("extensions.conf","globals",$app);
  $resAstConfig=putAstConfig("extensions.conf","globals",$app,$appdata);
  
  return true;
}

// ---- putAstConfig($file:string, $context:string, $var:string, $var_data:string): int 
function putAstConfig($file,$category,$var_name,$var_val,$comment="",$commented=0,$zsection=""){
  global $db;
  if ($file=="extensions.conf" and $asterikRealtime===true and $var_val!="Realtime/@extensions"){
    //**************************************************************************
    //                              ASTERISK REAL TIME
    //**************************************************************************

    //insert the realtime directive
    putAstConfig("extensions.conf", $category, "switch", "Realtime/@extensions");
    
    //extract the parameters
    ereg ("^(.*),(.*),(.[^(]*)\((.*)\)$", $var_val, $regs);
    $extension["context"]=$category;
    $extension["exten"]=$regs[1];
    $extension["priority"]=$regs[2];
    $extension["app"]=$regs[3];
    $extension["appdata"]=$regs[4]; 
    
    $table="extensions_table";
    $fields=$db->MetaColumnNames($table);
    foreach ($fields as $f) {
      if (array_key_exists($f,$extension) and $f!="id") {
        $field_list.="$f,";
        if (is_int($extension[$f])) $value_list.=$extension[$f].",";
        else  $value_list.="'".string2sql($extension[$f])."',";
      }
    }  
    $field_list=substr($field_list,0,-1);
    $value_list=substr($value_list,0,-1);
    
    //insert the row
    $qry="INSERT INTO $table ($field_list) VALUES ($value_list)";
    $res=$db->Execute($qry);
    if ($res===false) $ret=0; else $ret=$db->Insert_ID();
    return $ret;
    
  }else{  
    //**************************************************************************
    //                       ASTERISK STATIC - AST_CONFIG
    //**************************************************************************
    //if the same parameter entry is already into the table, do nothing else return entry id
    $qry="SELECT * FROM ast_config ";
    $qry.="WHERE filename='".string2sql($file)."' ";
    $qry.="AND category='".string2sql($category)."' ";
    $qry.="AND var_name='".string2sql($var_name)."' ";
    $qry.="AND var_val='".string2sql($var_val)."' ";
    $qry.="AND zsection='".string2sql($zsection)."' ";;
    $res=$db->Execute($qry);
    if(($res!==false)&&($arr=$res->FetchRow())){
      return $arr["id"];  
    }
    //calculate the var_metric
    $qry="SELECT * FROM ast_config ";
    $qry.="WHERE filename='".$file."' ";
    $qry.="AND category='".$category."' ";
    $res=$db->Execute($qry);
    if($res===false) return 0;
    $count=$res->RecordCount();
    if($count>0){
      $arrCat=$res->FetchRow();
      $qry="SELECT MAX(var_metric) as maxvar FROM ast_config WHERE filename='".string2sql($file)."' AND category='".string2sql($category)."'";
      $res=$db->Execute($qry);
      if(($res!==false)&&($arr=$res->FetchRow())){
        $var_metric=$arr["maxvar"]+1;
        $cat_metric=$arrCat["cat_metric"];
      }else return 0;
    }else{
      $qry="SELECT MAX(cat_metric) as maxcat FROM ast_config WHERE  filename='".string2sql($file)."'";
      $res=$db->Execute($qry);
      if(($res!==false)&&($arr=$res->FetchRow())){
        $cat_metric=$arr["maxcat"]+1;
        $var_metric=0;
      }else return 0;
    }
    //insert in ast_config and get entry id
    $qry="INSERT INTO ast_config (cat_metric,var_metric,commented,filename,category,var_name,var_val,comment,zsection) ";
    $qry.="VALUES ('".string2sql($cat_metric)."','".string2sql($var_metric)."','".string2sql($commented)."','".string2sql($file)."',";
    $qry.="'".string2sql($category)."','".string2sql($var_name)."','".string2sql($var_val)."','".string2sql($comment)."','".string2sql($zsection)."')";
    $res=$db->Execute($qry);
    if($res===false) return 0;
    $astconfig_id=$db->Insert_ID();
    //Sort and Clean zapata channel section: 
    // - force cat_metric to 0 and order var_metric by zsection
    // - force "channels" attribute to be the last of the zsection
    if(($file=="zapata.conf")&&($category=="channels")){
      //move other contexts away from cat_metric 0
      $qry="SELECT DISTINCT `category` FROM ast_config WHERE filename='zapata.conf' AND cat_metric='0' ";
      $res=$db->Execute($qry);
      if(($res!==false)&&($arr=$res->FetchRow())){
        $qry="UPDATE `ast_config` SET `cat_metric`='".string2sql($cat_metric)."' WHERE `category`='".string2sql($arr["category"])."'";
        $db->Execute($qry);
      }
      //sort zapata.conf and force "channels" attribute to be the last of the zsection
      $qry="SELECT `id`,`var_name`,`zsection` "; 
      $qry.="FROM ast_config ";
      $qry.="WHERE filename='zapata.conf' ";
      $qry.="AND category='channels' ";
      $qry.="ORDER BY zsection, var_metric";
      $res=$db->Execute($qry);
      if($res!==false){
        $var_metric = 0;
        $zsection="";
        $ch=0;
        while($arr=$res->FetchRow()){
          if(trim($arr["var_name"])=="channel"){
            $ch=$arr["id"];
            continue;
          }
          if($zsection!=$arr["zsection"]){
            if($zsection!=""){
              $qry="UPDATE `ast_config` SET `cat_metric`='0',`var_metric`='".string2sql($var_metric)."' WHERE `id`='".string2sql($ch)."'";
              $db->Execute($qry);
              $var_metric++;
            }
            $zsection=$arr["zsection"];
          }
          $qry="UPDATE `ast_config` SET `cat_metric`='0',`var_metric`='".string2sql($var_metric)."' WHERE `id`='".string2sql($arr["id"])."'";
          $db->Execute($qry);
          $var_metric++;
        }
        if($ch!=0){
          $qry="UPDATE `ast_config` SET `cat_metric`='0',`var_metric`='".string2sql($var_metric)."' WHERE `id`='".string2sql($ch)."'";
          $db->Execute($qry);
        }
      }
    }
    //return
    return $astconfig_id;
  }
}
// --- write additional parameters to delete settings of previous zsection
function optimizeAstConfig($tech){
  global $db;
  if($tech==ZAP){
    $techArr=getTechnology($tech);
    if((!is_array($techArr))||(!is_array($techArr[0]))) return false;
    $file=$techArr[0]["config_file"];
    $category=$techArr[0]["general_context"];
    //delete optimized options
    $qry="DELETE FROM ast_config ";
    $qry.="WHERE filename='".string2sql($file)."' ";
    $qry.="AND category like '".string2sql($category)."' ";
    $qry.="AND comment like '".string2sql("automatlicty inserted to ovewride prevoius settings")."' ";
    $res=$db->Execute($qry);
    //get ast_config
    $defaultSetting=array();
    $settings=array();
    $qry="SELECT zsection,var_name,var_val ";
    $qry.="FROM ast_config ";
    $qry.="WHERE filename='".string2sql($file)."' ";
    $qry.="AND category like '".string2sql($category)."' ";
    $qry.="ORDER BY var_metric ";
    $res=$db->Execute($qry);
    if($res!==false){
      $num=-1;
      $zsection="";
      while($arr=$res->FetchRow()){
        if(trim($arr["var_name"])=="") continue;
        if(trim($arr["zsection"])==""){
          $defaultSetting[$arr["var_name"]]=$arr["var_val"];
        }else{
          if($arr["zsection"]!=$zsection){$zsection=$arr["zsection"];$num++;}
          $settings[$num][]=array(
              "zsection" => $zsection,
              "var_name" => $arr["var_name"],
              "var_val" => $arr["var_val"]
            );
        }
      }
    }
    //overwrite params of previous zsection with defalut value
    for($i=1;$i<count($settings);$i++){
      //previous zsections option array
      $tmp=array();
      for($j=0;$j<$i;$j++){
        $tmp=array_merge($tmp,$settings[$j]);
      }
      $prevSettings=array();
      for($j=0;$j<count($tmp);$j++){
        $prevSettings[$tmp[$j]["var_name"]]=$tmp[$j]["var_val"];
      }
      //zsection options array
      $zsection=$settings[$i][0]["zsection"];
      $zsectionArr=array();
      for($j=0;$j<count($settings[$i]);$j++){
        $zsectionArr[$settings[$i][$j]["var_name"]]=$settings[$i][$j]["var_val"];
      }
      //option arrays diff
      $diffArr=array_diff_key($prevSettings,$zsectionArr);
      if(is_array($diffArr)){
        foreach($diffArr as $var_name=>$var_val){
          //retrieve defaul value in default settings
          if((is_array($defaultSetting))&&(array_key_exists($var_name,$defaultSetting))){
            $def_val=$defaultSetting[$var_name];
          }
          //retrive default value for option in zapata options
          else{
            $option=getOptionByName($var_name,"ZAP");
            $def_val=$option[0]["default"];
          }
          putAstConfig($file,$category,$var_name,$def_val,"automatlicty inserted to ovewride prevoius settings",0,$zsection);
        }
      }
    }
    return true;
  }
}
// ---- delAstConfig($file:string, $context:string, $var:string): bool 
function delAstConfig($file,$category,$var_name="",$var_val="",$zsection="") {
  global $db;
  //check input parameters
  if ($category=="" or $file=="") return false;
  //remove from ast_config table
  $qry="DELETE FROM ast_config ";
  $qry.="WHERE filename='".string2sql($file)."' ";
  $qry.="AND category like '".string2sql($category)."' ";
  $qry.="AND zsection='".string2sql($zsection)."' "; 
  if($var_name!="") $qry.=" AND var_name like '".string2sql($var_name)."'";
  if($var_val!="") $qry.=" AND var_val like '".string2sql($var_val)."'";
  $res=$db->Execute($qry);
  return $res;
}
// ---- setSystemName($name:string): int 
function setSystemName($system_name){
  global $db;
  //check input parameters
  if(trim($system_name)=="") return 0;
  //get system name option
  $systemOptionArr=getOptionByName("hostname","SYSTEM");
  if((!is_array($systemOptionArr))||(!is_array($systemOptionArr[0]))){
    return 0;
  }
  $option_id=$systemOptionArr[0]["id"];
  //remove from ast_config table
  $qry="UPDATE cw_option set value='".string2sql($system_name)."' WHERE id=".$option_id."";
  $res=$db->Execute($qry);
  if($res===false) return 0;
  //return
  return 1;
}




  if (!function_exists("file_put_contents")) {
     function file_put_contents($filename,$content,$mode="w") {
       if(!$file = @fopen($filename, $mode)) return false;
       if($file) {
         if(!@fwrite($file,$content)) return false;
         fclose($file);
         @chmod($file, 0755);
       }
       return true;
     }
  }

  if (!function_exists("file_get_contents")) {
    function file_get_contents($filename, $use_include_path = 0) {
      $data = ""; // just to be safe. Dunno, if this is really needed
      $file = @fopen($filename, "rb", $use_include_path);
      if ($file) {
        while (!feof($file)) $data .= fread($file, 1024);
        fclose($file);
      }
      return $data;
    }
  }


/**
 * Convert an XML data structure that is *read from file* into an array.
 * 
 * Array stucture: Node:[0]['name]=TAG opened; [0]['text']=Value [0]['closetag']=TAG closed; [0]['elements']=Array of subnode
 * @param string $xml filename with xml data to read and convert. 
 * @return array $xmlary reflecting structure
 * @todo separate file_get_contents from the function. This function should not read the file but take only the the xml string!
 */ 
  if (!function_exists("xml2array")) {
    function xml2array ($xml) {
    
      $xmlary = array ();
  
       if ((strlen ($xml) < 256) && is_file ($xml)) {
         $xml = file_get_contents ($xml);
       }
    
       $ReElements = '/<(\w+)\s*([^\/>]*)\s*(?:\/>|>(.*?)<(\/\s*\1\s*)>)/s';
       $ReAttributes = '/(\w+)=(?:"|\')([^"\']*)(:?"|\')/';

       preg_match_all ($ReElements, $xml, $elements);
       
       foreach ($elements[1] as $ie => $xx) {         
         $xmlary[$ie]["name"] = $elements[1][$ie]; 
        
         if ( $attributes = trim($elements[2][$ie])) {
           preg_match_all ($ReAttributes, $attributes, $att);
           foreach ($att[1] as $ia => $xx) {
             // all the attributes for current element are added here
             $xmlary[$ie]["attributes"][$att[1][$ia]] = $att[2][$ia];
           }           
         } // if $attributes
       
         // get text if it's combined with sub elements
         $cdend = strpos($elements[3][$ie],"<");
         if ($cdend > 0) {
           $xmlary[$ie]["text"] = substr($elements[3][$ie],0,$cdend -1);
         } // if cdend
         
         if (preg_match ($ReElements, $elements[3][$ie])){        
           $xmlary[$ie]["elements"] = xml2array ($elements[3][$ie]);
         } else if (isset($elements[3][$ie])) {
           $xmlary[$ie]["text"] = $elements[3][$ie];
         }
         
         $xmlary[$ie]["closetag"] = $elements[4][$ie];
       
       } //foreach 
     
       return $xmlary;
    } 
  }
  
  if (!function_exists("errArr")) {
    function errArr($arr) {
      if (count($arr)==0) error_log("ok!");
      else {
        ob_start();
          print_r($arr);
        $contents=ob_get_contents();
        ob_end_clean();
        error_log($contents);
      }
      return;
    }
  }

  //convert a string in a sql compatible string
  function string2sql($txt){
    if(get_magic_quotes_runtime()==0){ //get_magic_quotes_gpc()
      //$txt=str_replace("'","\\'",$txt);
      $txt=addslashes($txt);
    }
    return $txt;
  }
  //recursive array search for multidimensional array
  function array_key_exists_recursive($needle,$haystack){
  	if(is_array($haystack)){
      foreach($haystack as $key=>$val) {
        if(is_array($val)){ if($ret=array_key_exists_recursive($needle,$val)) return $ret; }
        else if($val == $needle) return true;
      }
    }
    return false;
  }
  /* OLD IMPLEMENTATION
  function array_key_exists_recursive($needle,$haystack,$id=0){
    foreach($haystack as $key=>$val) {
      if(is_array($val)) { if($ret=array_key_exists_recursive($needle,$val,$key)) return $ret; }
      elseif($val == $needle) return $id;
    }
    return 0;
  }
  */
  //verify if vo-tools is executable
  function isVotoolsExecutable(){
  	global $voiceoneWSDocumentRoot;
    if(!((fileperms($voiceoneWSDocumentRoot."/config/script/vo-tools.sh") & 0x0001))){
    	return $voiceoneWSDocumentRoot."/config/script/vo-tools.sh";
    } 
    return "1";
  }
  //verify database access
  function checkDatabaseAccess(){
  	global $db;
    if($db===false) return 0; 
    return "1";
  }  
    
  
/**
 * CALL FINDER
 */
/*
function setTarget($name,$number,$description) {
  global $db;
  $qry="INSERT INTO `rubrica` (`name` , `number` , `description`) ";
  $qry.="VALUES ('".string2sql($name)."', '".string2sql($number)."', '".string2sql($description)."'); ";
  $res=$db->Execute($qry); 
  if($res===false) return 0; else return 1;
}  
function delTargets() {
  global $db;
  $qry="TRUNCATE TABLE `rubrica` ";
  $res=$db->Execute($qry); 
  $qry="TRUNCATE TABLE `cdr` ";
  $res=$db->Execute($qry); 
  $qry="TRUNCATE TABLE `incomingcall` ";
  $res=$db->Execute($qry); 
  if($res===false) return 0; else return 1;
}   
function getTargetCalls() {
  global $db;
  $qry="SELECT incomingcall.`id`,rubrica.`name`,rubrica.`number`,rubrica.`description`,cdr.`disposition` ";
  $qry.="FROM rubrica JOIN incomingcall ON rubrica.`number` = incomingcall.`caller_number` ";
  $qry.="LEFT OUTER JOIN cdr ON incomingcall.`id` = cdr.`uniqueid` ";
  $res=$db->Execute($qry); 
  while($arr=$res->FetchRow()) {
    if((!isset($arr["disposition"]))||($arr["disposition"]=="")) $arr["disposition"]="INCOMING";
    $ret[]=$arr;
  }
  return $ret;
}   
*/
  
  
?>
